java-多线程深入(五)Atomic分析
2015-05-28 08:41
330 查看
(一)Atomic的使用
java.util.concurrent中提供了atomic原子包,可以实现原子操作(atomic operation),即在多线程环境中,执行的操作不会被其他线程打断。
运行结果:
最终结果:1000
多个线程对AtomicInteger类型的变量进行自增操作,运算结果无误。若用普通的int变量,i++多线程操作可能导致结果有误。
(二)原理分析
源码分析:
incrementAndGet函数
方法不断获取value值再进行递增操作,直至操作成功。
(三)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值。
java.util.concurrent中提供了atomic原子包,可以实现原子操作(atomic operation),即在多线程环境中,执行的操作不会被其他线程打断。
/** * 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函数
/** * 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; } }
private volatile int value;value是volatile类型,确保此线程能获取到最新值。
方法不断获取value值再进行递增操作,直至操作成功。
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值。
相关文章推荐
- Java多线程(一)之volatile深入分析
- 【Java多线程之ConcurrentHashMap深入分析】
- Java 多线程深入分析(一)
- Java多线程(七)之同步器基础:AQS框架深入分析
- Java多线程 -- JUC包源码分析9 -- AbstractQueuedSynchronizer深入分析-- Semaphore与CountDownLatch
- Java多线程(一)之volatile深入分析
- Java多线程(四)之ConcurrentSkipListMap深入分析
- Java多线程(五)之BlockingQueue深入分析
- Java多线程之线程池深入分析
- 针对Java多线程对BlockingQueue深入分析解析
- 【深入分析Java多线程】(5)synchronized和volatile分析
- 【Java并发编程】深入分析AtomicInteger(二)
- Java多线程(五)之BlockingQueue深入分析
- Java多线程(五)之BlockingQueue深入分析
- java多线程(四)之ConcurrentSkipListMap深入分析
- Java多线程 之BlockingQueue深入分析
- Java多线程(十一)之线程池深入分析(上)
- Java多线程(四)之ConcurrentSkipListMap深入分析
- java多线程-深入分析ConcurrentHashMap
- 【Java多线程之ConcurrentSkipListMap深入分析】