我阅读了几篇关于并发问题的文章,但我仍然不确定某些事情。 我可以说当使用 synchronized 时,我可以免费获得 volatile 功能,因为当一个对象上的锁将被释放时,下一个线程总是读取修改后的对象。使用 volatile,对象的值会立即反射(reflect)到其他线程。但是当我使用synchronized时,由于对象上的锁,不可能立即反射(reflect)出来。当锁被释放时,只有这样另一个线程才能访问它。所以我不必关心立即将值反射(reflect)给其他线程。我理解的对吗?
[更新]
示例始终打印 1 2 3 4 5 6 7 8 9,不带 volatile。
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 内存模型,同步访问并不暗示 volatile 访问(尽管在特定实现中可能是这样,但您不应该依赖于此)
Java Language Specification 17.4.4 (on the Java Memory Model):
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).
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).
volatile
对变量进行操作,synchronized
对对象的监视器(“锁”)进行操作。
如果一个线程 A 刚刚退出对象 O 上的同步块(synchronized block),而另一个线程 B 刚刚读取对象 上的易失变量(实例字段)V>O,那么两个线程之间仍然不同步关系。无法保证线程 A 会看到线程 B 所做的任何数据修改,反之亦然,直到线程 B 也在对象 O 上同步,或者直到线程 A 也访问了可变字段 V 在对象 O 上。
关于Java 使用 synchronized 时,我是否可以免费获得 volatile 功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23180112/