Java 为什么我需要对volatile上的多个线程使用synchronized?
有些人说,如果多个线程正在读/写,那么您需要使用synchronized;如果一个线程正在读/写,而另一个线程仅在读,那么您必须使用volatile。我不明白这两种情况之间的区别 基本上,一个volatile字段的值在写操作完成后对所有读卡器(特别是其他线程)都可见Java 为什么我需要对volatile上的多个线程使用synchronized?,java,multithreading,Java,Multithreading,有些人说,如果多个线程正在读/写,那么您需要使用synchronized;如果一个线程正在读/写,而另一个线程仅在读,那么您必须使用volatile。我不明白这两种情况之间的区别 基本上,一个volatile字段的值在写操作完成后对所有读卡器(特别是其他线程)都可见 然后,如果我将一个变量定义为volatile,首先threadA将读取它的值,threadA将更新它的值并将其写入内存。之后,threadB将看到该变量。那么为什么我需要同步阻止呢?正如评论所建议的,您可能需要进一步阅读。但是,为了
然后,如果我将一个变量定义为volatile,首先threadA将读取它的值,threadA将更新它的值并将其写入内存。之后,threadB将看到该变量。那么为什么我需要同步阻止呢?正如评论所建议的,您可能需要进一步阅读。但是,为了给你一个想法,你可以看看这个,然后思考以下场景: 有几个变量需要处于正确的状态。但是,尽管您使它们都不稳定,但您需要时间通过执行一些代码来更新它们 这段代码几乎可以由不同的线程同时执行。第一个变量可能是“OK”的,并且以某种方式进行了同步,但是其他一些变量可能依赖于第一个变量,并且还不正确。因此,在这种情况下需要一个同步块
为了进一步阅读volatile,再添加一篇文章,volatile和synchronized的主要区别在于volatile只保证可见性,而synchronized同时保证可见性和锁定 如果有多个读线程和一个写线程,那么volatile用法可以确保写线程对volatile变量的更改对其他线程立即可见。但在本例中,锁定不是问题,因为您只有一个写入线程 对于易失性,有一些经验法则:
synchronized
或volatile
更多地取决于对象的更新方式,而不是读写器的数量
例如,您可以使用AtomicLong
实现多个读写器,它封装了volatile long
private AtomicLong counter = new AtomicLong();
...
// many threads can get/set this counter without synchronized
counter.incrementAndGet();
在某些情况下,即使只有一个读写器,您也需要一个同步的块
synchronized (status) {
status.setNumTransactions(dao.getNumTransactions());
// we don't want the reader thread to see `status` partially updated here
status.setTotalMoney(dao.getTotalMoney());
}
在上面的示例中,由于我们正在进行多个调用以更新状态
对象,因此我们可能需要确保其他线程在更新num事务(而不是总金额)时不会看到它。是的,AtomicReference
处理其中一些情况,但不是全部
明确地说,标记字段volatile
可确保内存同步。当您读取一个volatile
字段时,您会跨越一个读取内存屏障,而当您写入该字段时,您会跨越一个写入内存屏障。synchronized
块的开头有一个读内存屏障,结尾有一个写屏障,并且具有互斥锁,以确保一次只能有一个线程进入该块
有时您只需要内存屏障来实现线程之间的数据正确共享,有时您需要锁定。我建议您做一些。这个问题比你意识到的要复杂得多。但举一个简单的例子-如果我想原子化设置两个变量呢?还建议:“Java并发性在实践中”@dnault,这似乎有点太高级了,如果你试图原子化设置两个变量,您将使用volatile定义这两个变量,并且在第一个线程完成其任务之前,volatile字段的值对于所有其他线程都是不可见的。顺便说一下,你的链接支持我的想法。如果您将c变量定义为volatile,您就不需要再同步方法了。@hellzone非常非常错误而且非常危险的词c++
和c--
不是原子操作,而且volatile
对您没有帮助。欢迎来到并发世界…一个易失性变量的值对于所有其他线程都是不可见的。“不同线程几乎可以同时执行代码”的方式“@hellzone,但在本例中,需要更新两个变量。假设我有一个类ConcurrentList
,现在我有一个数据
和一个大小
。我需要1)写入数据
,2)以原子方式更新大小。如果我首先更新大小
,并允许其他线程读取它,它们将读取尚未存在的数据。如果我先更新数据
,那么其他线程可能会覆盖我的数据,因为没有设置大小
volatile
是一个非常专业的并发构造。@hellzone也许我遗漏了一些东西,但是为什么变量对所有其他线程都不可见呢?我对volatile的理解是读写直接进入主内存(无缓存)——仅此而已——无阻塞/无cl