java.util.concurrent.atomic.AtomicInteger(Atomic详解)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a303549861/article/details/53016757
先上一段自己写的代码:
public class AtomicUse {
    private static AtomicInteger count = new AtomicInteger(0);
    //多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性
    /**synchronized*/
    public synchronized int multiAdd(){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count.addAndGet(1);
            count.addAndGet(2);
            count.addAndGet(3);
            count.addAndGet(4); //+10
            return count.get();
    }
    public static void main(String[] args) {
        final AtomicUse au = new AtomicUse();
        List<Thread> ts = new ArrayList<Thread>();
        for (int i = 0; i < 100; i++) {
            ts.add(new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(au.multiAdd());
                }
            }));
        }
        for(Thread t : ts){
            t.start();
        }
    }
}
运行结果: 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300 310 320 330 340 350 360 370 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 740 750 760 770 780 790 800 810 820 830 840 850 860 870 880 890 900 910 920 930 940 950 960 970 980 990 1000

(一)Atomic的使用

Java.util.concurrent中提供了atomic原子包,可以实现原子操作(atomic operation),即在多线程环境中,执行的操作不会被其他线程打断。

  1. /** 
  2.  * atomic简单demo 
  3.  *  
  4.  * @author peter_wang 
  5.  * @create-time 2014-6-9 上午9:29:58 
  6.  */  
  7. public class AtomicDemo  
  8.     extends Thread {  
  9.   
  10.   
  11.     private static final AtomicInteger TEST_INT = new AtomicInteger();  
  12.   
  13.   
  14.     @Override  
  15.     public void run() {  
  16.         TEST_INT.incrementAndGet();  
  17.     }  
  18.   
  19.   
  20.     /** 
  21.      * @param args 
  22.      */  
  23.     public static void main(String[] args) {  
  24.         for (int i = 0; i < 1000; i++) {  
  25.             AtomicDemo demo = new AtomicDemo();  
  26.             demo.start();  
  27.             try {  
  28.                 demo.join();  
  29.             }  
  30.             catch (InterruptedException e) {  
  31.                 e.printStackTrace();  
  32.             }  
  33.         }  
  34.           
  35.         System.out.println(”最终结果:”+TEST_INT);  
  36.     }  
  37.   
  38.   
  39. }  
/**
 * atomic简单demo
 * 
 * @author peter_wang
 * @create-time 2014-6-9 上午9:29:58
 */
public class AtomicDemo
    extends Thread {


    private static final AtomicInteger TEST_INT = new AtomicInteger();


    @Override
    public void run() {
        TEST_INT.incrementAndGet();
    }


    /**
     * @param args
     */
    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            AtomicDemo demo = new AtomicDemo();
            demo.start();
            try {
                demo.join();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        System.out.println("最终结果:"+TEST_INT);
    }


}

运行结果:

最终结果:1000

多个线程对AtomicInteger类型的变量进行自增操作,运算结果无误。若用普通的int变量,i++多线程操作可能导致结果有误。

(二)原理分析

源码分析:

incrementAndGet函数

  1. /** 
  2.      * Atomically increments by one the current value. 
  3.      * 
  4.      * @return the updated value 
  5.      */  
  6.     public final int incrementAndGet() {  
  7.         for (;;) {  
  8.             //获取当前值value  
  9.             int current = get();  
  10.             int next = current + 1;  
  11.             //循环执行到递增成功  
  12.             if (compareAndSet(current, next))  
  13.                 return next;  
  14.         }  
  15.     }  
/**
     * Atomically increments by one the current value.
     *
     * @return the updated value
     */
    public final int incrementAndGet() {
        for (;;) {
            //获取当前值value
            int current = get();
            int next = current + 1;
            //循环执行到递增成功
            if (compareAndSet(current, next))
                return next;
        }
    }
  1. private volatile int value;  
private volatile int value;
value是volatile类型,确保此线程能获取到最新值。

方法不断获取value值再进行递增操作,直至操作成功。

  1. public final boolean compareAndSet(int expect, int update) {  
  2.     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  3.     }  
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
compareAndSet使用Unsafe调用native本地方法CAS(CompareAndSet) 递增数值。

(三)CAS简要

CAS利用CPU调用底层指令实现。

单一处理器,进行简单的读写操作时,能保证自身读取的原子性,多处理器或复杂的内存操作时,CAS采用总线加锁或缓存加锁方式保证原子性。

1.总线加锁

如i=0初始化,多处理器多线程环境下进行i++操作下,处理器A和B同时读取i值到各自缓存,分别进行递增,回写值i=1相同。处理器提供LOCK#信号,进行总线加锁后,处理器A读取i值并递增,处理器B被阻塞不能读取i值。

2.缓存加锁

总线加锁,在LOCK#信号下,其他线程无法操作内存,性能较差,缓存加锁能较好处理该问题。

缓存加锁,处理器A和B同时读取i值到缓存,处理器A提前完成递增,数据立即回写到主内存,并让处理器B缓存该数据失效,处理器B需重新读取i值。



(一)Atomic的使用

Java.util.concurrent中提供了atomic原子包,可以实现原子操作(atomic operation),即在多线程环境中,执行的操作不会被其他线程打断。

  1. /** 
  2.  * atomic简单demo 
  3.  *  
  4.  * @author peter_wang 
  5.  * @create-time 2014-6-9 上午9:29:58 
  6.  */  
  7. public class AtomicDemo  
  8.     extends Thread {  
  9.   
  10.   
  11.     private static final AtomicInteger TEST_INT = new AtomicInteger();  
  12.   
  13.   
  14.     @Override  
  15.     public void run() {  
  16.         TEST_INT.incrementAndGet();  
  17.     }  
  18.   
  19.   
  20.     /** 
  21.      * @param args 
  22.      */  
  23.     public static void main(String[] args) {  
  24.         for (int i = 0; i < 1000; i++) {  
  25.             AtomicDemo demo = new AtomicDemo();  
  26.             demo.start();  
  27.             try {  
  28.                 demo.join();  
  29.             }  
  30.             catch (InterruptedException e) {  
  31.                 e.printStackTrace();  
  32.             }  
  33.         }  
  34.           
  35.         System.out.println(”最终结果:”+TEST_INT);  
  36.     }  
  37.   
  38.   
  39. }  
/**
 * atomic简单demo
 * 
 * @author peter_wang
 * @create-time 2014-6-9 上午9:29:58
 */
public class AtomicDemo
    extends Thread {


    private static final AtomicInteger TEST_INT = new AtomicInteger();


    @Override
    public void run() {
        TEST_INT.incrementAndGet();
    }


    /**
     * @param args
     */
    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            AtomicDemo demo = new AtomicDemo();
            demo.start();
            try {
                demo.join();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        System.out.println("最终结果:"+TEST_INT);
    }


}

运行结果:

最终结果:1000

多个线程对AtomicInteger类型的变量进行自增操作,运算结果无误。若用普通的int变量,i++多线程操作可能导致结果有误。

(二)原理分析

源码分析:

incrementAndGet函数

  1. /** 
  2.      * Atomically increments by one the current value. 
  3.      * 
  4.      * @return the updated value 
  5.      */  
  6.     public final int incrementAndGet() {  
  7.         for (;;) {  
  8.             //获取当前值value  
  9.             int current = get();  
  10.             int next = current + 1;  
  11.             //循环执行到递增成功  
  12.             if (compareAndSet(current, next))  
  13.                 return next;  
  14.         }  
  15.     }  
/**
     * Atomically increments by one the current value.
     *
     * @return the updated value
     */
    public final int incrementAndGet() {
        for (;;) {
            //获取当前值value
            int current = get();
            int next = current + 1;
            //循环执行到递增成功
            if (compareAndSet(current, next))
                return next;
        }
    }
  1. private volatile int value;  
private volatile int value;
value是volatile类型,确保此线程能获取到最新值。

方法不断获取value值再进行递增操作,直至操作成功。

  1. public final boolean compareAndSet(int expect, int update) {  
  2.     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  3.     }  
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
compareAndSet使用Unsafe调用native本地方法CAS(CompareAndSet) 递增数值。

(三)CAS简要

CAS利用CPU调用底层指令实现。

单一处理器,进行简单的读写操作时,能保证自身读取的原子性,多处理器或复杂的内存操作时,CAS采用总线加锁或缓存加锁方式保证原子性。

1.总线加锁

如i=0初始化,多处理器多线程环境下进行i++操作下,处理器A和B同时读取i值到各自缓存,分别进行递增,回写值i=1相同。处理器提供LOCK#信号,进行总线加锁后,处理器A读取i值并递增,处理器B被阻塞不能读取i值。

2.缓存加锁

总线加锁,在LOCK#信号下,其他线程无法操作内存,性能较差,缓存加锁能较好处理该问题。

缓存加锁,处理器A和B同时读取i值到缓存,处理器A提前完成递增,数据立即回写到主内存,并让处理器B缓存该数据失效,处理器B需重新读取i值。



猜你喜欢

转载自blog.csdn.net/a303549861/article/details/53016757
今日推荐