Singleton class 和 volatile 变量的组合
Combination of Singleton class and volatile variable
据我所知,volatile变量总是会从主存中读写。然后想到了Singletonclass。这是我的程序是这样的:
1。单例 class
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。主要 class
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 class 中的 static volatile int count
变量将始终具有最新值,但显然它没有......
有人能帮我理解一下吗?
非常感谢。
问题是volatile
与线程同步无关。即使从 static volatile int count
读取确实总是 return 最新值,多个线程也可能将相同的新值写回它。
用两个线程考虑这个场景:
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
。
正如 Jon Skeet 所说,最好使用 AtomicInteger
。使用 volatile 变量可以降低内存一致性错误的风险,但并不能消除同步原子操作的需要。
我认为这个修改可以帮助您解决问题。
public synchronized String test(){
count++;
return ("Counted increased!" + count);
}
Reader 线程没有进行任何锁定,直到写入线程从同步块中出来,内存才会同步并且 'sin' 的值不会在主内存中更新。两个线程读取相同的值并因此通过添加一个来更新它,如果你想解决使测试方法同步。
阅读更多:http://javarevisited.blogspot.com/2011/06/volatile-keyword-java-example-tutorial.html#ixzz3PGYRMtgE
据我所知,volatile变量总是会从主存中读写。然后想到了Singletonclass。这是我的程序是这样的:
1。单例 class
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。主要 class
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 class 中的 static volatile int count
变量将始终具有最新值,但显然它没有......
有人能帮我理解一下吗?
非常感谢。
问题是volatile
与线程同步无关。即使从 static volatile int count
读取确实总是 return 最新值,多个线程也可能将相同的新值写回它。
用两个线程考虑这个场景:
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
。
正如 Jon Skeet 所说,最好使用 AtomicInteger
。使用 volatile 变量可以降低内存一致性错误的风险,但并不能消除同步原子操作的需要。
我认为这个修改可以帮助您解决问题。
public synchronized String test(){
count++;
return ("Counted increased!" + count);
}
Reader 线程没有进行任何锁定,直到写入线程从同步块中出来,内存才会同步并且 'sin' 的值不会在主内存中更新。两个线程读取相同的值并因此通过添加一个来更新它,如果你想解决使测试方法同步。
阅读更多:http://javarevisited.blogspot.com/2011/06/volatile-keyword-java-example-tutorial.html#ixzz3PGYRMtgE