Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.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_Synchronization_Thread Safety - Fatal编程技术网

我是否需要在Java中同步对不可变类型的访问?

我是否需要在Java中同步对不可变类型的访问?,java,multithreading,synchronization,thread-safety,Java,Multithreading,Synchronization,Thread Safety,假设我有一门课: class Zoo { protected String bearName; protected Double trainerSalary; protected Integer monkeyCount; } 一个线程可以写入这些字段,另一个线程可以读取它们,而不需要同步访问Zoo对象吗 注意:这些值可以彼此分开处理,因此在读取monkeyCount时更改trainerSalary并不重要 编辑: 只是澄清一下,字段是可变的;只有它们引用的对象是不可变的

假设我有一门课:

class Zoo
{
    protected String bearName;
    protected Double trainerSalary;
    protected Integer monkeyCount;
}
一个线程可以写入这些字段,另一个线程可以读取它们,而不需要同步访问Zoo对象吗

注意:这些值可以彼此分开处理,因此在读取monkeyCount时更改trainerSalary并不重要

编辑:


只是澄清一下,字段是可变的;只有它们引用的对象是不可变的。

如果这些变量确实是独立的,那么就不需要同步。然而,正如你所注意到的,如果你

protected Integer monkeysLeft;
protected Integer monkeysEatenByBears;

如果这两个变量在逻辑上是连接的,则您希望同步访问这对变量。

如果这些变量确实是独立的,则不需要同步。然而,正如你所注意到的,如果你

protected Integer monkeysLeft;
protected Integer monkeysEatenByBears;

如果这两个变量在逻辑上是连接的,您可能希望同步访问这对变量。

从技术上讲,您需要将它们设置为最终变量、易失变量或使用synchronized进行读写,以确保读卡器将读取最新的值。正如您现在看到的,如果一个线程写入一个值,则不能保证另一个线程将读取相同的值。这是因为读取线程可能会看到缓存的值。对于多核CPU和不同级别的缓存,这种情况更可能发生


这方面的一本好书是。

从技术上讲,您需要将它们设置为最终版本、易变版本或使用Synchronized进行读写,以确保读者能够读取最新的值。正如您现在看到的,如果一个线程写入一个值,则不能保证另一个线程将读取相同的值。这是因为读取线程可能会看到缓存的值。对于多核CPU和不同级别的缓存,这种情况更可能发生


这方面的一本好书是。

如您所述,同一个包中的另一个类可以更改这些值。这个类不是一成不变的

现在如果你做了类似的事情

class Zoo
{
    protected final String bearName;
    protected final Double trainerSalary;
    protected final Integer monkeyCount;
}
那么这个类将是不可变的。如果程序的逻辑将这个类视为不可变的,那么为什么不使它实际上不可变呢


此外,如果多个线程正在检查和更新相同的值,那么您可能会遇到问题。假设多个线程正在检查和更新monkeyCount,那么monkeyCount很有可能最终不正确,因为没有任何东西会强制这些检查和更新以原子方式进行

如您所述,同一个包中的另一个类可以更改这些值。这个类不是一成不变的

现在如果你做了类似的事情

class Zoo
{
    protected final String bearName;
    protected final Double trainerSalary;
    protected final Integer monkeyCount;
}
那么这个类将是不可变的。如果程序的逻辑将这个类视为不可变的,那么为什么不使它实际上不可变呢


此外,如果多个线程正在检查和更新相同的值,那么您可能会遇到问题。假设多个线程正在检查和更新monkeyCount,那么monkeyCount很有可能最终不正确,因为没有任何东西会强制这些检查和更新以原子方式进行

对与除long或double之外的任何类型的字段对应的存储单元的访问和更新都保证是原子的。这就是为什么人们可能认为您不需要同步对字段的读取访问。但是,Java内存模型允许线程缓存以前读取的值,以防您重复访问它们,因此您应该将字段标记为volatile,以确保每个线程都能看到最新的值

如果您确定没有人会更改字段的值,请将其设置为最终值。在这种情况下,不需要易失性字段


如果字段的值相互依赖,情况就不同了。在这种情况下,我建议使用同步设置器,以确保不违反类的不变量。

对与除long或double之外的任何类型的字段对应的内存单元的访问和更新都保证是原子的。这就是为什么人们可能认为您不需要同步对字段的读取访问。但是,Java内存模型允许线程缓存以前读取的值,以防您重复访问它们,因此您应该将字段标记为volatile,以确保每个线程都能看到最新的值

如果您确定没有人会更改字段的值,请将其设置为最终值。在这种情况下,不需要易失性字段


如果字段的值相互依赖,情况就不同了。在这种情况下,我建议使用同步设置器,以确保不违反类的不变量。

我的2美分,来自Java编程语言,第4版,14.10.2: 有一种常见的误解,即对不可变对象的共享访问不需要任何同步,因为对象的状态永远不会改变。这通常是一种误解,因为它依赖于一个线程将是guar的假设 我想去看电影 不可变对象的初始化状态,不必如此。问题在于,虽然共享对象是不可变的,但用于访问共享对象的引用本身是共享的,并且通常是可变的——因此,正确同步的程序必须同步对该共享引用的访问,但程序通常不会这样做,因为程序员没有意识到这样做的必要性。例如,假设一个线程创建一个字符串对象,并将对该对象的引用存储在静态字段中。然后,第二个线程使用它
引用来访问字符串。根据我们到目前为止讨论的内容,无法保证在构造字符串时第一个线程写入的值在第二个线程访问字符串时会被第二个线程看到。

我的2美分,摘自Java编程语言,第4版,14.10.2: 有一种常见的误解,即对不可变对象的共享访问不需要任何同步,因为对象的状态永远不会改变。这通常是一种误解,因为它依赖于这样一种假设,即保证线程能够看到 不可变对象的初始化状态,不必如此。问题在于,虽然共享对象是不可变的,但用于访问共享对象的引用本身是共享的,并且通常是可变的——因此,正确同步的程序必须同步对该共享引用的访问,但程序通常不会这样做,因为程序员没有意识到这样做的必要性。例如,假设一个线程创建一个字符串对象,并将对该对象的引用存储在静态字段中。然后,第二个线程使用它
引用来访问字符串。根据我们到目前为止讨论的内容,无法保证在构造字符串时第一个线程写入的值在第二个线程访问字符串时会被第二个线程看到。

是什么使这些值不可变?如果你可以写它们,它们需要通过某种形式的同步来保护。@Rodney Gitzel:我认为这意味着对象本身是不可变的。您不能保留对字符串的引用并更改创建新对象所需的内容。@Rodney Gitzel String、Double和Integer在Java中都是不可变的类型。做任何改变它们的工作只会返回一个新对象。Zoo在其字段中使用不可变对象并不重要。这并不是说动物园一成不变。不变性意味着一旦创建,您将不会更改Zoo中的任何内容。现在,如果Zoo确实是不可变的,那么您的问题的答案是否定的,您不需要同步对Zoo的访问。是什么使这些值不可变?如果你可以写它们,它们需要通过某种形式的同步来保护。@Rodney Gitzel:我认为这意味着对象本身是不可变的。您不能保留对字符串的引用并更改创建新对象所需的内容。@Rodney Gitzel String、Double和Integer在Java中都是不可变的类型。做任何改变它们的工作只会返回一个新对象。Zoo在其字段中使用不可变对象并不重要。这并不是说动物园一成不变。不变性意味着一旦创建,您将不会更改Zoo中的任何内容。现在,如果Zoo确实是不可变的,那么您的问题的答案是否定的,您不需要同步对Zoo的访问。volatile或synchronized是防止两个不同线程从同一线程获取不同值的关键,同时,我建议您在列举备选方案时也提到java.util.concurrent.atomic包中的类?这是不进行任何显式同步的另一种方法。volatile或synchronized是防止两个不同线程同时从同一线程获取不同值的关键。我建议您在列举备选方案时也提及java.util.concurrent.atomic包中的类?这是另一种没有显式同步的方法。如果一个线程正在向它们写入,而另一个线程正在按照他的建议读取它们,那么它们无论如何都需要同步。如果一个线程正在向它们写入,而另一个线程正在按照他的建议读取它们,那么它们无论如何都需要同步。访问和更新内存单元与除long或double之外的任何类型的字段相对应的字段都保证是原子的-真的吗?我以前从未见过任何记录这件事的东西。对不起,忘了提到来源。它来自Doug Leas的《Java并发编程》@Finbarr@Sebastian Zarnekow,这实际上来自于。对与除long或double之外的任何类型字段对应的内存单元的访问和更新都保证是原子的-真的吗?我以前从未见过任何记录这件事的东西。对不起,忘了提到来源。它来自Doug Leas的《Java并发编程》@Finbarr@Sebastian Zarnekow,这实际上来自。