繁体   English   中英

Java使用synchronized时我是否免费获得易失性功能?

[英]Java When using synchronized do I get volatile functionality for free?

我读了几篇关于并发性问题的帖子,但我仍然不确定某些事情。 我可以说当使用synchronized时,我免费获得易失性功能,因为当释放对象的锁定时,下一个线程总是读取修改后的对象。 对于volatile,对象的值会立即反映到其他线程。 但是当我使用synchronized时,由于对象的锁定,不可能立即反映它。 释放锁定后,只有另一个线程可以访问它。 所以我不必关心立即将值反映到其他线程。 我理解这个吗?

[UPDATE]
示例打印总是1 2 3 4 5 6 7 8 9没有易失性。

package main;

public class Counter
{
    public static long count = 0;
}

public class UseCounter implements Runnable
{
    public void increment()
    {
        synchronized (this)
        {       
            Counter.count++;
            System.out.print(Counter.count + " ");
        }
    }

    @Override
    public void run()
    {
        increment();
        increment();
        increment();
    }
}

public class DataRace
{
    public static void main(String args[])
    {
        UseCounter c = new UseCounter();

        Thread t1 = new Thread(c);
        Thread t2 = new Thread(c);
        Thread t3 = new Thread(c);

        t1.start();
        t2.start();
        t3.start();
    }
}

不,根据Java内存模型,同步访问并不暗示易失性访问(尽管在特定实现中,它可能是,但您不应该依赖于此)

Java语言规范17.4.4(关于Java内存模型):

同步动作引发与动作的同步关系,定义如下:

  • 监视器m上的解锁动作与m上的所有后续锁定动作同步(其中“后续”根据同步顺序定义)。

  • 对易失性变量v(第8.3.1.4节)的写入与任何线程对v的所有后续读取同步(其中“后续”根据同步顺序定义)。

volatile对变量进行操作,并在对象的监视器(“锁定”)上进行synchronized操作。

如果一个线程A刚刚退出对象O上的同步块,而另一个线程B刚刚读取了对象O上的volatile变量(实例字段) V ,则两个线程之间仍然没有同步关系。 无法保证线程A将看到线程B完成的任何数据修改,反之亦然,直到线程B也在对象O上同步,或者直到线程A也访问对象O上的易失性字段V.

拥有volatile变量与同步访问不同。 将变量标记为volatile时,访问该对象的Thread对象将不会保留本地缓存,并且只会有一个“副本”。 如果你将两者(synchronized和volatile)结合起来,那么它将始终是更新版本,并且你不会有相互冲突的访问权限。

您的代码保证打印1 2 3 4 5 6 7 8 9.原因是如果您有一个序列,如

  1. 线程t1写入Counter.count
  2. 线程t1解锁对象c
  3. 线程t2锁定对象c
  4. 线程t2读取Counter.count

然后保证步骤4的读取在步骤1看到写入。

这与volatile因为不能保证写入立即反映回存储器,而是仅保证步骤1中的写入在步骤3结束时对t2可见。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM