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

时间:2014-04-20 08:36:52

标签: java multithreading concurrency synchronized volatile

我读过几篇关于并发性问题的帖子,但我仍然不确定某些事情。 我可以说当使用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();
    }
}

3 个答案:

答案 0 :(得分:2)

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

Java Language Specification 17.4.4 (on the Java Memory Model):

  

同步动作会导致同步关系   行动,定义如下:

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

  •   
  • 对volatile变量v(第8.3.1.4节)的写入与all同步   随后通过任何线程读取v(其中定义了“后续”)   根据同步顺序)。

  •   

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

如果一个线程A刚刚退出对象 O 上的同步块,而另一个线程B刚刚读取了对象 V > O ,那么两个线程之间仍然存在同步关系。无法保证线程A将看到线程B完成的任何数据修改,反之亦然,直到线程B也在对象 O 上同步,或者直到线程A也访问volatile字段 V on object O

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

  1. 线程t1写入Counter.count
  2. 线程t1解锁对象c
  3. 线程t2锁定对象c
  4. 线程t2读取Counter.count
  5. 然后保证步骤4的读取在步骤1看到写入。

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