java并发编程(一)-从入门到吐血

一:初始原子类

在并发编程中,若多个线程同时操作同一变量就有问题了,比如:

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


你可能感兴趣的:(java并发编程(一)-从入门到吐血)