热门搜索 :
考研考公
您的当前位置:首页正文

从数1000个数中看并发

来源:东饰资讯网

从1数到1000,有如下类:

class Calculate {

    static int count = 0

    def static inc() {

        try {
            Thread.sleep(1)
        } catch (Exception e) {

        }

        count++
        println count

    }
}

开始数:

class Test {

    public static void main(String[] args) {

        for (int i in 1..1000) {
            new Thread(new Runnable() {
                @Override
                void run() {
                    Calculate.inc()
                }
            }).start()
        }
    }

}

结果很接近但并不是预想的1000.

这要从jvm运行时刻的内存分配来解释这个问题。每个线程运行时都有一个线程栈,存放线程运行时的变量,当线程需要访问某一个对象时,会通过引用找到对应的堆内存地址,并把对应堆内存中的值加载到线程工作内存中,建立一个堆内存中的值的副本,在线程修改完值之后会再把副本写回到对象的堆内存中。
由于读取写回等操作并不是原子操作,当主内存的值发生改变时,并不会影响线程工作内存中的值,所以计算结果和预期并不一样。

这时候就要对自增操作进行加锁。

class Calculate {

    static int count = 0

    def static inc() {

        synchronized (Calculate.class) {

            try {
                Thread.sleep(1)
            } catch (Exception e) {

            }

            count++
            println count
        }
    }
}

开始数:

class Test {

    public static void main(String[] args) {

        for (int i in 1..1000) {
            new Thread(new Runnable() {
                @Override
                void run() {
                    Calculate.inc()
                }
            }).start()
        }
    }

}

还有volatile修饰的变量并不能保证在并发情况的正确性。jvm虚拟机只能保证从主内存加载到线程工作内存中的值是最新的。

不加锁static volatile int count = 0 这样解决不了问题。

Top