一:初始原子类
在并发编程中,若多个线程同时操作同一变量就有问题了,比如:
public class Calculate {
private int num;
public void add() {
try {
for(int i=0;i<200;i++){
Thread.sleep(100);
num++;
System.out.println(num);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
上面写了一个类,里面有一个循环200次自增1的方法,这时我们启动三个线程同时调用这个方法,我们都知道,会有线程安全问题,如下:
public class Test {
public static void main(String[] args){
Calculate calculate = new Calculate();
for(int i=0;i<3;i++){
new Thread(){
@Override
public void run() {
calculate.add();
}
}.start();
}
}
}
正常的话最后num会变成600,但实际上却不是,会比600小,因为会出现多个线程同时修改了这个数。
这时我们一般会在 产生竞争条件的地方加上锁,也就是 num++这里;
synchronized (this) {
num++;
System.out.println(num);
}
这样可以解决问题,不过我们都知道加锁效率会变低,其实java1.5后给我们提供了原子类,顾名思义,该操作是原子性的,其粒度更细,因为竞争范围缩小到了单个变量上。
原子操作类都在下面这个包下:java.util.concurrent.atomic,每个类都有各自的方法。
所以上面Calculate类可以改成:其中
new AtomicInteger();//括号里可以填初始值
public class Calculate {
private AtomicInteger num = new AtomicInteger();
public void add() {
try {
for(int i=0;i<200;i++){
Thread.sleep(100);
System.out.println(num.getAndIncrement());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试发现一切正常。
二:Volatile-保证多线程中变量的可见性
先看以下代码:
public class Test { private static boolean boo; public static void main(String[] args) throws InterruptedException { new Thread(){ @Override public void run() { for(;;){ if(boo){ System.out.println(boo+"==="); System.exit(0); } } } }.start(); Thread.sleep(50); new Thread(){ @Override public void run() { for(;;){ boo = true; } } }.start();}正常来说这段代码控制台最终肯定会有输出的,只是时间长短问题,但经过测试我们会发现,程序会卡死,这是为什么呢?
由于CPU速度太快,而读内存很慢,所有在CPU和主内存之间会有缓存,上面的程序中第一个线程从缓存中取到boo的值是false,它不会去读内存,不知道boo的值已经改变了,所以会一直运行下去,但如果在变量前加上volatile关键字,则程序就可以结束并有结果输出。
因为加了volatile后,就可以保证变量的修改让所有线程看见!关于volatile关键字的详细,可参看下面这篇文章:
http://www.cnblogs.com/xrq730/p/7048693.html