Java并发包使用及源码浅析(原子类Atomic)

原子类(Atomic)

 在并发编程中,对于一成员变量有多个线程在对它进行读写操作,如何保证它的线程安全性?java中提供synchronized块、被synchronized修饰的方法、volatile(实际上不并不是线程安全的)、以及本文将介绍的原子操作类。原子操作类有AtomicInteger、AtomicBoolean、AtomicLong、AtomicReference<V>等

一、synchronized关键字:

synchronized大家都比较熟悉,通过 synchronized 关键字来实现,所有加上synchronized 和 块语句,在多线程访问的时候,同一时刻只能有一个线程能够用,这样就保证了线程的安全性,synchronized用法暂不做介绍,具体使用请移步:
http://www.jianshu.com/p/ea9a482ece5f


二、volatile关键字

1、计数器示例

有一个main线程会创建5000个线程来修改Counter类的count变量,最后打印count的值,按照预期conut的值应该是5000,可实际上并不是如此,代码如下:

public class Counter {

    private volatile static int count = 0;

    /**
     * 增加
     */
    public static void increment() {
        count++;
    }
    /**
     * 获取值
     * @return
     */
    public static int get() {
        return count;
    }

    public static void main(String[] args) {

        //创建5000个线程来对Counter进行增加操作
        for (int i = 0; i < 5000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.increment();
                }
            }).start();
        }
        //阻塞2秒是为了防止主线程先执行完。
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("计算结果:" + Counter.get());
    }
}

以下是代码运行结果:

这里写图片描述

所以volatile并不能保证count的值正确,为什么会产生这样的结果呢?

程序中申明synchronized会有两个效果该代码具有 原子性(atomicity)和 可见性(visibility)。
1、原子性-原子性意味着个时刻,只有一个线程能够执行一段代码,这段代码通过一个monitor object保护。从而防止多个线程在更新共享状态时相互冲突。
2、可见性-可见性则更为微妙,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的。 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。
http://www.ibm.com/developerworks/cn/Java/j-jtp06197.html

volatile具有可见性,但无原子性,count值的写入要依赖于count当前的值,count++操作看上去就一句代码,实际上它是一个由(读取-修改-写入)操作序列组成的组合操作,而且要以原子性进行,显然volatile是满足不了的,所以volatile的使用条件必须同时满足下面两个条件:

  • 对变量的写操作不依赖于当前值。
  • 该变量没有包含在具有其他变量的不变式中。

三、AtomicInteger

同上面的计数器,++操作改为AtomicInteger来实现,代码如下:

public class AtomicCounter {

    public  static AtomicInteger ai = new AtomicInteger(0);

    /**
     * 增加
     */
    public static void increment() {
        ai.incrementAndGet();
    }
    /**
     * 获取值
     * @return
     */
    public static int get(){
        return ai.get();
    }

    public static void main(String[] args) {

        //创建5000个线程来对Counter进行增加操作
        for (int i = 0; i < 5000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    AtomicCounter.increment();
                }
            }).start();
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
      //阻塞2秒是为了防止主线程先执行完。
        System.out.println("计算结果:" + AtomicCounter.get());
    }
}

以下是代码运行结果:

这里写图片描述

要实现类似计数器的效果用AtomicInteger无疑是最好的方式之一,AtomicBoolean、AtomicLong、AtomicReference等提供多元化的原子操作, 原子操作实现原理请移步:

http://ifeve.com/atomic-operation/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值