有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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) 个答案

  1. # 1 楼答案

    这两种数据结构都是线程安全的。因此,线程上的每个孤立操作都是安全的

    问题在于,当它们之间存在依赖关系时,执行多个操作

    在您的情况下,检查存在性必须与实际操作一致,以避免竞争条件。 要添加新堆栈,可以使用putIfAbsent方法,该方法是原子的且不同步

    要删除堆栈,不需要检查是否存在。如果想知道它是否存在,只需返回remove方法返回值。如果为空,则表示它不存在

    要执行push和pop,只需首先获取堆栈并分配给局部变量。如果为空,则表示它不存在。如果它不为空,则可以安全地推送或弹出

    属性myStacks必须是final或volatile才能保证线程安全

    现在你不需要任何同步。我会选择一个没有例外的解决方案。只是为了增加一个新的堆栈,它似乎更有必要。如果它可以在正确的程序中发生,那么它应该是一个已检查的异常。当运行时异常被认为是一个bug时,它更合适

    哦,还有triplecheck并测试它,因为并发编程很棘手