据我所知,volatile变量总是会从主内存中读取和写入。然后我想到了Singleton类。以下是我的计划:
1。单身人士班级
public class Singleton {
private static Singleton sin;
private static volatile int count;
static{
sin = new Singleton();
count = 0;
}
private Singleton(){
}
public static Singleton getInstance(){
return sin;
}
public String test(){
count++;
return ("Counted increased!" + count);
}
}
2。主要课程
public class Java {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Derived d1 = new Derived("d1");
d1.start();
Derived d2 = new Derived("d2");
d2.start();
Derived d3 = new Derived("d3");
d3.start();
}
;
}
class Derived extends Thread {
String name;
public Derived(String name){
this.name = name;
}
public void run() {
Singleton a = Singleton.getInstance();
for (int i = 0; i < 10; i++) {
System.out.println("Current thread: "+ name + a.test());
}
}
}
我知道这可能是一个愚蠢的问题,但我不擅长Java中的多线程,因此这个问题让我很困惑。我认为Singleton类中的static volatile int count
变量将始终具有最新值,但显然它不...
有人可以帮我理解吗?
非常感谢你。
答案 0 :(得分:5)
问题是volatile
与线程同步无关。即使来自static volatile int count
的读取确实总是返回最新值,但多个线程可能会将相同的新值写回其中。
考虑这个场景有两个线程:
count is initialized zero
Thread A reads count, sees zero
Thread B reads count, sees zero
Thread A advances count to 1, stores 1
Thread B advances count to 1, stores 1
Thread A writes "Counted increased! 1"
Thread B writes "Counted increased! 1"
两个线程都读取最新值,但由于++
不是原子操作,因此一旦读取完成,每个线程都是独立的。两个线程独立计算下一个值,然后将其存储回count
变量。净效果是变量递增一次,即使两个线程都执行了增量。
如果您想从多个主题增加int
,请使用AtomicInteger
。
答案 1 :(得分:0)
正如Jon Skeet所说,最好使用AtomicInteger
。使用volatile变量可以降低内存一致性错误的风险,但不会消除同步原子操作的需要。
我认为这种修改可以帮助解决您的问题。
public synchronized String test(){
count++;
return ("Counted increased!" + count);
}
答案 2 :(得分:0)
读取器线程没有进行任何锁定,并且在编写器线程从同步块中出来之前,内存将不会被同步,并且“&#39; sin&#39;将不会在主内存中更新。两个线程读取相同的值,因此如果要解析make test方法同步,则通过添加一个来更新它。
了解详情:http://javarevisited.blogspot.com/2011/06/volatile-keyword-java-example-tutorial.html#ixzz3PGYRMtgE