AtomicInteger

AtomicInteger是java.util.concurrent.atomic包下面的原子操作类,可以用原子方式更新int值。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排它性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个其它线程进入。

示例代码:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerDemo {

    public static AtomicInteger count=new AtomicInteger(0);

    public static void inc(){
        try{
            Thread.sleep(1); //延迟1毫秒
        }catch (Exception e){
            e.printStackTrace();
        }
        //获取当前值并自增,增长因子为1
        count.getAndIncrement();
    }

    public static void main(String[] args) throws InterruptedException{
        final CountDownLatch latch = new CountDownLatch(100);
        for (int i=0;i<100;i++) {
            new Thread(new Runnable() {
                public void run() {
                    inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();
        System.out.println("运行结果:"+count.get());
    }
}

运行结果:

100

注意:此处先是创建了100个线程,并且这些线程都是处于就绪状态(等待被调度),latch.await()方法使当前主线程处于阻塞状态。在1毫秒的时间内。几乎这100个线程的任务全部都调度过,当前全都在等待进入到count.getAndIncrement()中,但由于该实例(AtomicInteger )的方法(getAndIncrement)在一个时间点只能被一个线程所调用,因此对于AtomicInteger类来操作int值是线程安全的。

 

对于上述操作如果我们直接采用的int类型的变量来作为共享变量的话,代码如下

import java.util.concurrent.CountDownLatch;

public class AtomicIntegerDemo {

    public static int count = 0;

    public static void inc(){
        try{
            Thread.sleep(1); //延迟1毫秒
        }catch (Exception e){
            e.printStackTrace();
        }
        count++;
    }

    public static void main(String[] args) throws InterruptedException{
        final CountDownLatch latch = new CountDownLatch(100);
        for (int i=0;i<100;i++) {
            new Thread(new Runnable() {
                public void run() {
                    inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();
        System.out.println(count);
    }
}

运行结果:

97或者98或者99

从运行结果可以看出,直接采用int类型的变量作为共享变量时,会出现线程安全的问题。解决办法就是对于上述操作,我们可以在inc方法前面加上synchronized关键字来同步代码块,即

public synchronized static void inc(){...}

加上了synchronized后虽然处理了线程安全问题,但是其运行的时间变长了,我的电脑为4核(即4个CPU),测试其运行时间为0.18ms,但是如果使用AtomicInteger的话,其运行时间为0.009ms,AtomicInteger避免了synchronized的高开销,执行效率大为提升。

结论:在共享变量为基本数据类型(int类型)时,如果可能会出现线程安全问题时,尽量采用AtomicInteger原子操作类;其它情况下还是直接使用int类型。

扩展:

AtomicBoolean:可以用原子方式更新boolean的值

AtomicLong:可以用原子方式更新long值

AtomicReference:可以用原子方式更新对象引用

以上三个扩展的原子操作类都可以参考AtomicInteger的代码示例进行测试

你可能感兴趣的:(并发编程)