简体   繁体   English

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

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

I read several posts about concurrency problems but I'm still unsure about something. 我读了几篇关于并发性问题的帖子,但我仍然不确定某些事情。 Can I say that when using synchronized, I get volatile functionality for free, because when the lock on an object will be released, the next thread always reads the modified object. 我可以说当使用synchronized时,我免费获得易失性功能,因为当释放对象的锁定时,下一个线程总是读取修改后的对象。 With volatile, the value of an object is immediately reflected to other threads. 对于volatile,对象的值会立即反映到其他线程。 But when I use synchronized, there is no possibility to immediately reflect it due to the lock on the object. 但是当我使用synchronized时,由于对象的锁定,不可能立即反映它。 When the lock is released, only then another thread may access it. 释放锁定后,只有另一个线程可以访问它。 So I don't have to care about reflecting the value immediately to other threads. 所以我不必关心立即将值反映到其他线程。 Do I understand this right? 我理解这个吗?

[UPDATE] [UPDATE]
Example prints always 1 2 3 4 5 6 7 8 9 without volatile. 示例打印总是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();
    }
}

No, a volatile access is not implied by synchronized access according the the Java Memory Model (although on particular implementations, it may be, but you should not depend on that) 不,根据Java内存模型,同步访问并不暗示易失性访问(尽管在特定实现中,它可能是,但您不应该依赖于此)

Java Language Specification 17.4.4 (on the Java Memory Model): Java语言规范17.4.4(关于Java内存模型):

Synchronization actions induce the synchronized-with relation on actions, defined as follows: 同步动作引发与动作的同步关系,定义如下:

  • An unlock action on monitor m synchronizes-with all subsequent lock actions on m (where "subsequent" is defined according to the synchronization order). 监视器m上的解锁动作与m上的所有后续锁定动作同步(其中“后续”根据同步顺序定义)。

  • A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order). 对易失性变量v(第8.3.1.4节)的写入与任何线程对v的所有后续读取同步(其中“后续”根据同步顺序定义)。

volatile operates on a variable and synchronized operates on the monitor (the 'lock') of an object. volatile对变量进行操作,并在对象的监视器(“锁定”)上进行synchronized操作。

If one Thread A has just exited a synchronized block on object O , and another Thread B has just read a volatile variable (instance field) V on object O , then there is still not a synchronized-with relation between the two threads. 如果一个线程A刚刚退出对象O上的同步块,而另一个线程B刚刚读取了对象O上的volatile变量(实例字段) V ,则两个线程之间仍然没有同步关系。 There is no guarantee that Thread A will see any data modifications done by Thread B or vice versa, until Thread B also synchronized on object O , or until Thread A also accessed volatile field V on object O . 无法保证线程A将看到线程B完成的任何数据修改,反之亦然,直到线程B也在对象O上同步,或者直到线程A也访问对象O上的易失性字段V.

Having a volatile variable isn't the same as synchronized access. 拥有volatile变量与同步访问不同。 When you mark a variable as volatile, Thread objects accessing the object will not keep a local cache and there will only ever be one "copy". 将变量标记为volatile时,访问该对象的Thread对象将不会保留本地缓存,并且只会有一个“副本”。 If you combine the two (synchronized and volatile) then it will always be the updated version, and you won't have conflicting access of it. 如果你将两者(synchronized和volatile)结合起来,那么它将始终是更新版本,并且你不会有相互冲突的访问权限。

Your code is guaranteed to print 1 2 3 4 5 6 7 8 9. The reason is that if you have a sequence such as 您的代码保证打印1 2 3 4 5 6 7 8 9.原因是如果您有一个序列,如

  1. Thread t1 writes to Counter.count 线程t1写入Counter.count
  2. Thread t1 unlocks object c 线程t1解锁对象c
  3. Thread t2 locks object c 线程t2锁定对象c
  4. Thread t2 reads Counter.count 线程t2读取Counter.count

then it is guaranteed that the read at step 4 sees the write at step 1. 然后保证步骤4的读取在步骤1看到写入。

This is not the same as volatile because it is not guaranteed that the write is reflected back to memory immediately, rather it is only guaranteed that the write in step 1 is visible to t2 at the end of step 3. 这与volatile因为不能保证写入立即反映回存储器,而是仅保证步骤1中的写入在步骤3结束时对t2可见。

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

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