举例说明如何在Java中进行同步?

问题描述 投票:-1回答:1

我一直在告诉同事,他应该同步数据结构的方法,因为它是从不同的线程中进行更新,然后在另一个线程中进行查询。他认为没有必要这样做,因为所有线程都写入不同的字段,并且仅在所有写入它们的线程完成后才读取值。

现在,根据我二十岁对Java内存模型的理解,这肯定是错误的。如果没有同步,则有可能一个线程写入一个值,而另一个线程(在第一个线程完成之后)看不到该值(如果未完成同步)。我对当时的运作方式非常有信心。

我也认为始终同步多线程对共享数据结构的访问仍然是一个很好的通用原则。但是我需要更好的论据来说服我的同事。

但是自那时以来,我知道在Java内存模型上已经做了很多工作,使它在更多默认情况下可以做正确的事情,所以我的第一个问题是:我的理解仍然正确吗?在这种简单情况下(线程A更新字段,线程B在线程A完成后读取该字段),您是否仍应使用synchronized

其次,我正在寻找示例代码,这些代码演示了这种同步的必要性。 not确实使用了同步,并演示了一个线程在另一个线程已经明确写入该值之后读取了错误的值。我试图自己写点东西,但我无法打破。我只能找到的所有示例都是同步use的示例,而不是如果没有的话会出现问题的示例。我尝试过的所有方法即使没有同步也仍然可以工作,可能是因为它们很旧,并且自那时以来Java内存模型已经得到改进以使其能够正常工作。

有人可以在缺乏同步的情况下以这种方式提供一个简单的数据访问出错的例子吗?另外,最近有哪些不错的资料可以阅读有关同步或Java内存模型的当前状态的信息?

java multithreading synchronized
1个回答
0
投票

从技术上讲,您的同事是正确的。或者,在某些情况下,他/她可能会在。

相关问题是共享变量的写入和读取之间是否存在happens-before relationship

例如,建立这种关系的一种情况是,进行读取的线程在进行写入的线程上调用join以确保它在尝试读取该值之前已完成。

线程中的所有动作发生-在任何其他线程成功从该线程上的join()返回之前。

在这种情况下,这是安全的。例如:

class Foo {
  int a;

  void test() {
    Thread t = new Thread(() -> { a = 1; });

    t.start();

    // ...

    System.out.println(a); // Might print 0 or 1.

    // ...

    // This means that everything done by the thread happens before
    // everything that happens after this line. So, the write to `a`
    // happens before the read of `a`.
    t.join(); 

    System.out.println(a); // Will print 1, unless some other thread interferes with its value.

  }

}

但是,我不会称其为良好做法:这非常脆弱,因为它依赖于您不尝试在执行join -ing的线程中读取任何地方的值。

除非可以证明,同步是一个无法接受的性能问题,所以我会。

但是,实际上,我认为最好不要在这么低的级别上处理多线程的事情:使用ExecutorService,将Callable提交给它,这将返回线程将要写入的值,并使用返回Future以获得结果。

© www.soinside.com 2019 - 2024. All rights reserved.