Singleton类和volatile变量的组合

时间:2015-01-19 11:08:38

标签: java multithreading


据我所知,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变量将始终具有最新值,但显然它不...
有人可以帮我理解吗?
非常感谢你。

3 个答案:

答案 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