java如何在保持线程安全的同时降低锁定的粒度?
我有一组简单、受管理的堆栈,需要以线程安全的方式访问它们。我的第一个实现工作正常,但对所有访问都使用synchronized
方法,即锁定是最粗糙的级别。我想让锁定尽可能细化,但我不确定最好的方式
以下是我的Stack manager类的基础知识(为了简洁起见,省略了一些细节):
public class StackManager {
private final Map<String, Deque<String>> myStacks;
public StackManager() {
myStacks = new ConcurrentHashMap<String, Deque<String>>();
}
public synchronized void addStack(String name) {
if (myStacks.containsKey(name)) {
throw new IllegalArgumentException();
}
myStacks.put(name, new ConcurrentLinkedDeque<String>());
}
public synchronized void removeStack(String name) {
if (!myStacks.containsKey(name)) {
throw new IllegalArgumentException();
}
myStacks.remove(name);
}
public synchronized void push(String stack, String payload) {
if (!myStacks.containsKey(stack)) {
throw new IllegalArgumentException();
}
myStacks.get(stack).push(payload);
}
public synchronized String pop(String stack) {
if (!myStacks.containsKey(stack)) {
throw new IllegalArgumentException();
}
return myStacks.get(stack).pop();
}
}
堆栈级别的方法(addStack()、removeStack())并不经常使用。然而,我想知道他们的锁定水平是否可以降低。例如,如果这些方法不同步,并在myStacks
上建立锁,这会减少争用吗?比如
public void addStack(String name) {
synchronized(myStacks) {
if (myStacks.containsKey(name)) {
throw new IllegalArgumentException();
}
myStacks.put(name, new ConcurrentLinkedDeque<String>());
}
}
每堆栈方法(push()、pop())是我认为可以获得最多收益的地方。如果可能的话,我想实现每堆栈锁定。也就是说,只锁定正在操作的堆栈管理器中的单个堆栈。然而,我看不到一个好办法来做到这一点。有什么建议吗
在这里,有必要同时使用Map和Deque的实现吗
# 1 楼答案
这两种数据结构都是线程安全的。因此,线程上的每个孤立操作都是安全的
问题在于,当它们之间存在依赖关系时,执行多个操作
在您的情况下,检查存在性必须与实际操作一致,以避免竞争条件。 要添加新堆栈,可以使用putIfAbsent方法,该方法是原子的且不同步
要删除堆栈,不需要检查是否存在。如果想知道它是否存在,只需返回remove方法返回值。如果为空,则表示它不存在
要执行push和pop,只需首先获取堆栈并分配给局部变量。如果为空,则表示它不存在。如果它不为空,则可以安全地推送或弹出
属性myStacks必须是final或volatile才能保证线程安全
现在你不需要任何同步。我会选择一个没有例外的解决方案。只是为了增加一个新的堆栈,它似乎更有必要。如果它可以在正确的程序中发生,那么它应该是一个已检查的异常。当运行时异常被认为是一个bug时,它更合适
哦,还有triplecheck并测试它,因为并发编程很棘手