您的位置:首页 > 编程语言 > Java开发

Java并发下的count++问题

2016-01-20 15:46 465 查看
需要深入理解volatile请看方腾飞的博客:

http://ifeve.com/volatile/

引用自 http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html

Java中的原子操作包括:

除long和double之外的基本类型的赋值操作

所有引用reference的赋值操作

java.concurrent.Atomic.* 包中所有类的一切操作

count++不是原子操作,是3个原子操作组合:

读取主存中的count值,赋值给一个局部成员变量tmp

tmp+1

将tmp赋值给count

可能会出现线程1运行到第2步的时候,tmp值为1;这时CPU调度切换到线程2执行完毕,count值为1;切换到线程1,继续执行第3步,count被赋值为1————结果就是两个线程执行完毕,count的值只加了1;

还有一点要注意,如果使用AtomicInteger.set(AtomicInteger.get()+1),会和上述情况一样有并发问题,要使用AtomicInteger.getAndIncrement()才可以避免并发问题

package com.lianglin.test;

public class VolatileTest {

static class MyObject{

static int mycount=0;

}

public static void inc() {

MyObject.mycount++;

}

public static void main(String[] args) {

//同时启动1000个线程,去进行i++计算,看看实际结果

for (int i = 0; i < 1000; i++) {

new Thread(new Runnable() {

@Override

public void run() {

inc();

}

}).start();

}

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

};

//这里每次运行的值都有可能不同,可能为1000

System.out.println(“运行结果:Counter.count=” +MyObject.mycount);

}

}

每次输出值都是:1000

注意:

对于值引用来说,多线程操作的是变量的副本,操作完后刷新到主存中。而对于地址引用,多线程是通过地址操作的是同一个变量。volatitle关键字告诉编译器,直接去通过地址操作变量,而不是变量的副本

2016-01-22更新
使用volatitle关键字:jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的,意即还是变量的副本.


一切重点都在于对于值引用来说,线程保存的是值的副本!如果count =1 ,

在走到第二步拷贝值到本地后,如果cpu切换到另一个线程完成了 count++ 那么内存中的count = 2

而此时第一个线程的副本还是1,此时再做count++并赋值给内存中的count,相当于并没有+1,只是重复赋值了一次
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: