我读过几篇关于并发性问题的帖子,但我仍然不确定某些事情。 我可以说当使用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();
}
}
答案 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.原因是如果您有序列,例如
然后保证步骤4的读取在步骤1看到写入。
这与volatile
不同,因为不能保证写入立即反映回内存,而只保证步骤1中的写入在步骤3结束时对t2可见