Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 返回引用时是否获取锁_Java_Multithreading - Fatal编程技术网

Java 返回引用时是否获取锁

Java 返回引用时是否获取锁,java,multithreading,Java,Multithreading,我正在浏览CMISAPI的源代码。其中一种方法定义如下 public OperationContext getDefaultContext() { lock.readLock().lock(); try { return defaultContext; } finally { lock.readLock().unlock(); } } 我想知道,在返回引用时是否需要获取锁?如果需要,我为什么要获得锁?锁的目的之一是建立所谓的先发生

我正在浏览CMISAPI的源代码。其中一种方法定义如下

public OperationContext getDefaultContext() {
    lock.readLock().lock();
    try {
        return defaultContext;
    } finally {
        lock.readLock().unlock();
    }
}

我想知道,在返回引用时是否需要获取锁?如果需要,我为什么要获得锁?

锁的目的之一是建立所谓的先发生后发生关系。计算机被允许对操作进行重新排序,这样你可能会直觉地认为“A,然后B”实际上在一个线程中看起来像“A,然后B”,但在另一个线程中看起来像“B,然后A”。同步所做的事情之一就是告诉计算机,“你必须先做A,然后做B。”

这可能导致非常混乱的情况。例如,您可以看到所谓的“部分写入”,线程只看到某个操作的一部分。想象一下,如果您在
defaultContext
上设置了两个变量:
defaultContext.a=“a”;defaultContext.b=“b”。包括return语句,您有三个操作:读取
defaultContext
(返回),以及写入a和b。线程可以看到它们的顺序是
defaultContext.b=“b”;返回默认上下文;defaultContext.a=“a”。第三个可能会晚很多,甚至永远不会来!换句话说,该线程将看到写入
defaultContext.b
,但不会看到写入
defaultContext.a
:部分写入

在这种情况下,A和B是对变量
defaultLock
的写入和读取。如果多个线程正在访问
defaultLock
(即使有人读它,而其他人只写它),那么您需要同步,以便每个线程都有一个完全最新的
defaultContext
。你在告诉电脑:“那些写给A和B的信,真的必须在回来之前寄来。”

请注意,要使其正常工作,您必须小心地进行设置,因为对
defaultContext
的任何后续写入都不会同步。您必须让一个线程执行对局部变量的所有写入操作(即,创建和初始化默认上下文),然后在保持
lock
的写入锁的同时将该局部变量写入
defaultContext
,然后再没有其他线程可以修改
defaultContext
。在这种情况下,有一种更简单的方法:只需将
defaultContext
设置为
volatile
字段,其写入和读取具有类似的before-before关系。我无法推测代码的作者为什么没有这么做


假设您正在查看的代码是OpenCMIS的,这似乎就是正在发生的事情。对defaultContext的所有读取都是通过粘贴的getDefaultContext方法完成的,所有写入都是通过使用writeLock的setDefaultContext完成的。

锁定的目的之一是建立所谓的“先发生后发生”关系。计算机被允许对操作进行重新排序,这样你可能会直觉地认为“A,然后B”实际上在一个线程中看起来像“A,然后B”,但在另一个线程中看起来像“B,然后A”。同步所做的事情之一就是告诉计算机,“你必须先做A,然后做B。”

这可能导致非常混乱的情况。例如,您可以看到所谓的“部分写入”,线程只看到某个操作的一部分。想象一下,如果您在
defaultContext
上设置了两个变量:
defaultContext.a=“a”;defaultContext.b=“b”。包括return语句,您有三个操作:读取
defaultContext
(返回),以及写入a和b。线程可以看到它们的顺序是
defaultContext.b=“b”;返回默认上下文;defaultContext.a=“a”。第三个可能会晚很多,甚至永远不会来!换句话说,该线程将看到写入
defaultContext.b
,但不会看到写入
defaultContext.a
:部分写入

在这种情况下,A和B是对变量
defaultLock
的写入和读取。如果多个线程正在访问
defaultLock
(即使有人读它,而其他人只写它),那么您需要同步,以便每个线程都有一个完全最新的
defaultContext
。你在告诉电脑:“那些写给A和B的信,真的必须在回来之前寄来。”

请注意,要使其正常工作,您必须小心地进行设置,因为对
defaultContext
的任何后续写入都不会同步。您必须让一个线程执行对局部变量的所有写入操作(即,创建和初始化默认上下文),然后在保持
lock
的写入锁的同时将该局部变量写入
defaultContext
,然后再没有其他线程可以修改
defaultContext
。在这种情况下,有一种更简单的方法:只需将
defaultContext
设置为
volatile
字段,其写入和读取具有类似的before-before关系。我无法推测代码的作者为什么没有这么做


假设您正在查看的代码是OpenCMIS的,这似乎就是正在发生的事情。对defaultContext的所有读取都是通过粘贴的getDefaultContext方法完成的,所有写入都是通过使用writeLock的setDefaultContext完成的。

这根本没有意义——至少在单独查看这一方法时是如此

这段代码可能会序列化获取该上下文对象的行为。但这样做毫无意义

当然,除非有一个以类似方式实现的相应setter。另一个答案很好地概括了此类构造如何为写入或读取底层字段的潜在调用创建顺序

但问题是:如果没有进一步的解释,这种隐性行为是非常隐蔽的。就我个人而言,我更喜欢一个更明确的解决方案。例如,不使用锁定