Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/384.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 为什么我需要对volatile上的多个线程使用synchronized?_Java_Multithreading - Fatal编程技术网

Java 为什么我需要对volatile上的多个线程使用synchronized?

Java 为什么我需要对volatile上的多个线程使用synchronized?,java,multithreading,Java,Multithreading,有些人说,如果多个线程正在读/写,那么您需要使用synchronized;如果一个线程正在读/写,而另一个线程仅在读,那么您必须使用volatile。我不明白这两种情况之间的区别 基本上,一个volatile字段的值在写操作完成后对所有读卡器(特别是其他线程)都可见 然后,如果我将一个变量定义为volatile,首先threadA将读取它的值,threadA将更新它的值并将其写入内存。之后,threadB将看到该变量。那么为什么我需要同步阻止呢?正如评论所建议的,您可能需要进一步阅读。但是,为了

有些人说,如果多个线程正在读/写,那么您需要使用synchronized;如果一个线程正在读/写,而另一个线程仅在读,那么您必须使用volatile。我不明白这两种情况之间的区别

基本上,一个volatile字段的值在写操作完成后对所有读卡器(特别是其他线程)都可见


然后,如果我将一个变量定义为volatile,首先threadA将读取它的值,threadA将更新它的值并将其写入内存。之后,threadB将看到该变量。那么为什么我需要同步阻止呢?

正如评论所建议的,您可能需要进一步阅读。但是,为了给你一个想法,你可以看看这个,然后思考以下场景:

有几个变量需要处于正确的状态。但是,尽管您使它们都不稳定,但您需要时间通过执行一些代码来更新它们

这段代码几乎可以由不同的线程同时执行。第一个变量可能是“OK”的,并且以某种方式进行了同步,但是其他一些变量可能依赖于第一个变量,并且还不正确。因此,在这种情况下需要一个同步块


为了进一步阅读volatile,再添加一篇文章,volatile和synchronized的主要区别在于volatile只保证可见性,而synchronized同时保证可见性和锁定

如果有多个读线程和一个写线程,那么volatile用法可以确保写线程对volatile变量的更改对其他线程立即可见。但在本例中,锁定不是问题,因为您只有一个写入线程

对于易失性,有一些经验法则:

  • 当volatile的值取决于它以前的值时,不要使用volatile
  • 当volatile参与与其他不变量的交互时,不要使用volatile
  • 当有多个写线程更新volatile变量的值时,不要使用volatile
  • 一般来说,volatile的使用应该仅限于那些相对容易解释其状态的情况,例如状态标志的情况

    在所有其他具有共享可变状态的情况下,除非声明为final并仅在构造函数中修改,否则在触及共享可变状态的任何位置都始终使用synchronized,而不使用不安全的发布。Volatile仅在特殊情况下替代synchronized,如我的3点所述

    有些人说,如果多个线程正在读/写,那么您需要使用synchronized;如果一个线程正在读/写,而另一个线程仅在读,那么您必须使用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