用什么例子来说明Java中同步的必要性?

用什么例子来说明Java中同步的必要性?,java,multithreading,synchronized,Java,Multithreading,Synchronized,我一直在告诉一位同事,他应该同步数据结构的方法,因为它正在从不同的线程更新,然后在另一个线程中查询。他认为没有必要这样做,因为线程都会写入不同的字段,而值只有在所有写入它们的线程都完成之后才被读取 现在,根据我二十年前对Java内存模型的理解,这肯定是错误的。如果没有同步,一个线程可能写入一个值,而另一个线程(在第一个线程完成后)可能看不到该值(如果没有进行同步)。我对我当时的理解很有信心 我还认为始终同步对共享数据结构的多线程访问仍然是一个很好的一般原则。但我需要更好的论据来说服我的同事 然而

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

现在,根据我二十年前对Java内存模型的理解,这肯定是错误的。如果没有同步,一个线程可能写入一个值,而另一个线程(在第一个线程完成后)可能看不到该值(如果没有进行同步)。我对我当时的理解很有信心

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

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

其次,我正在寻找示例代码,演示这种同步的必要性。不使用同步并在另一个线程已经明确写入错误值后演示线程读取错误值的东西。我试着自己写些东西,但我没能把它弄坏。我所能找到的所有例子都是使用同步的例子,而不是不使用同步会出现什么问题的例子。我尝试过的那些即使没有同步也仍然可以工作,可能是因为它们很旧,而且Java内存模型从那时起已经改进,使其能够正常工作


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

从技术上讲,你的同事是对的。或者,更确切地说,他/她在某些情况下可能是

相关的问题是共享变量的写入和读取之间是否存在冲突

例如,建立关系的一种情况是,执行读取操作的线程在执行写入操作的线程上调用
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.

  }

}
然而,我不认为这是一个好的实践:它非常脆弱,因为它依赖于除了在执行
连接的线程中之外,您不尝试在任何地方读取值

除非可以证明同步是一个不可接受的性能问题,否则我会这样做


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

“并且这些值只有在所有写入它们的线程都完成之后才被读取。”这取决于:是否使用
Thread.join()检查finished
在要读取值的线程中,存在“发生在之前”关系,因此它是安全的。不过,它感觉非常脆弱。请看一看,仅根据代码的模糊描述很难判断代码是否有效。至于“建议一个示例”,我打赌堆栈溢出不是此类请求的正确位置。Re,“如果没有同步,[线程a]可能会写入一个值,[然后线程B在线程a完成后无法看到该值。]”如果线程B调用
a.join()
,这就是同步。