【java总结】多线程进阶篇之atomic包
2017-02-20 08:49
309 查看
在java语言中,类似i++这种操作并不是原子性的。它并非线程安全的语句,在实际使用中,我们经常需要使用synchronized语句来保证数据的正确。现如今,大多数处理器都包含原子性指令,常见的指令是CAS(compare and set)和TAS(test
and set),是一种加锁的原子操作指令。
CAS 操作
包含三个操作数 ——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。CAS执行结果要么成功要么失败,对于失败的情形下一班采用不断重试。或者放弃。
在java.util.concurrent.atomic包中,所有类都使用了原子变量,它并不用同步来实现,因此大大提高了效率。
atomic包含有的类如下:
AtomicBoolean 可以用原子方式更新的 boolean 值。
AtomicInteger 可以用原子方式更新的 int 值。
AtomicIntegerArray 可以用原子方式更新其元素的 int 数组。
AtomicIntegerFieldUpdater<T> 基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。
AtomicLong 可以用原子方式更新的 long 值。
AtomicLongArray 可以用原子方式更新其元素的 long 数组。
AtomicLongFieldUpdater<T> 基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新。
AtomicMarkableReference<V> AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。
AtomicReference<V> 可以用原子方式更新的对象引用。
AtomicReferenceArray<E> 可以用原子方式更新其元素的对象引用数组。
AtomicReferenceFieldUpdater<T,V> 基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。
AtomicStampedReference<V> AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。
ABA问题:如果一个线程修改V值假设原来是A,先修改成B,再修改回成A。当前线程的CAS操作无法分辨当前V值是否发生过变化。举个例子,你把屋子收拾干净之后,有事出门一趟,这时屋子整齐的状态成为A,在你出门的这段时间,有人把你的屋子弄乱,翻来翻去。这时脏乱的状态成为B,之后,又帮你恢复到原样,当你回家的时候,你看到的是状态A,你以为你的屋子一直存在于状态A,而实际上它经历了ABA这个过程。
总结:使用atomic包下的各种类来处理线程线程之间的竞争要比使用synchronized关键字要高效的多,尽量使用原子类。
and set),是一种加锁的原子操作指令。
CAS 操作
包含三个操作数 ——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。CAS执行结果要么成功要么失败,对于失败的情形下一班采用不断重试。或者放弃。
在java.util.concurrent.atomic包中,所有类都使用了原子变量,它并不用同步来实现,因此大大提高了效率。
atomic包含有的类如下:
AtomicBoolean 可以用原子方式更新的 boolean 值。
AtomicInteger 可以用原子方式更新的 int 值。
AtomicIntegerArray 可以用原子方式更新其元素的 int 数组。
AtomicIntegerFieldUpdater<T> 基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。
AtomicLong 可以用原子方式更新的 long 值。
AtomicLongArray 可以用原子方式更新其元素的 long 数组。
AtomicLongFieldUpdater<T> 基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新。
AtomicMarkableReference<V> AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。
AtomicReference<V> 可以用原子方式更新的对象引用。
AtomicReferenceArray<E> 可以用原子方式更新其元素的对象引用数组。
AtomicReferenceFieldUpdater<T,V> 基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。
AtomicStampedReference<V> AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。
public class AtomicBooleanTest { /** 06. * 主要方法: 07. * @see AtomicBoolean#compareAndSet(boolean, boolean) 第一个参数为原始值,第二个参数为要修改的新值,若修改成功则返回true,否则返回false 08. * @see AtomicBoolean#getAndSet(boolean) 尝试设置新的boolean值,直到成功为止,返回设置前的数据 09. */ public final static AtomicBoolean TEST_BOOLEAN = new AtomicBoolean(); public static void main(String[] args){ for(int i=0;i<10;i++){ new Thread(){ public void run(){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } if(TEST_BOOLEAN.compareAndSet(false, true)){ System.out.println("我是线程"+Thread.currentThread().getName()+"我成功了!"); }else System.out.println("我是线程"+Thread.currentThread().getName()+"我失败了!"); } }.start(); } } }
public class AtomicIntegerTest { public final static AtomicInteger TEST_INTEGER=new AtomicInteger(1); public static void main(String[] args)throws InterruptedException { final Thread[] threads=new Thread[10]; for(int i=0;i<10;i++){ final int num=i; threads[i]=new Thread(){ public void run(){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } int now=TEST_INTEGER.incrementAndGet(); System.out.println("我是线程"+num+",我得到了值,增加后的值为:"+now); } }; threads[i].start(); } for(int i=0;i<10;i++){ threads[i].join(); } System.out.println("最终结果:"+TEST_INTEGER.get()); } }
public class AtomicIntegerArrayTest { private final static AtomicIntegerArray ATOMIC_INTEGER_ARRAY = new AtomicIntegerArray(new int[]{1,2,3,4,5,6,7,8,9,10}); public static void main(String []args) throws InterruptedException { Thread []threads = new Thread[100]; for(int i = 0 ; i < 100 ; i++) { final int index = i % 10; final int threadNum = i; threads[i] = new Thread() { public void run() { int result = ATOMIC_INTEGER_ARRAY.addAndGet(index, index + 1); System.out.println("线程编号为:" + threadNum + " , 对应的原始值为:" + (index + 1) + ",增加后的结果为:" + result); } }; threads[i].start(); } for(Thread thread : threads) { thread.join(); } System.out.println("=========================>\n执行已经完成,结果列表:"); for(int i = 0 ; i < ATOMIC_INTEGER_ARRAY.length() ; i++) { System.out.println(ATOMIC_INTEGER_ARRAY.get(i)); } } }
ABA问题:如果一个线程修改V值假设原来是A,先修改成B,再修改回成A。当前线程的CAS操作无法分辨当前V值是否发生过变化。举个例子,你把屋子收拾干净之后,有事出门一趟,这时屋子整齐的状态成为A,在你出门的这段时间,有人把你的屋子弄乱,翻来翻去。这时脏乱的状态成为B,之后,又帮你恢复到原样,当你回家的时候,你看到的是状态A,你以为你的屋子一直存在于状态A,而实际上它经历了ABA这个过程。
public class AtomicReferenceTest { public final static AtomicReference <String>ATOMIC_REFERENCE = new AtomicReference<String>("abc"); public static void main(String[] args){ for (int i=0;i<100;i++){ final int num=i; new Thread(){ @Override public void run(){ try{ Thread.sleep((int)(Math.random()*100)); }catch(InterruptedException e){ e.printStackTrace(); } if(ATOMIC_REFERENCE.compareAndSet("abc", "abc2")){ System.out.println("我是线程"+num+"我获得了锁进行了对象修改!"); } } }.start(); } new Thread(){ @Override public void run(){ while(!ATOMIC_REFERENCE.compareAndSet("abc2", "abc")); System.out.println("已经改为原始值!"); } }.start(); } }
public class AtomicStampedReferenceTest { /* * 将abc修改为abc2的线程仅有一个被访问,虽然被修改回了原始值,但 * 是其他线程也不会再将abc改为abc2。 */ public final static AtomicStampedReference <String>ATOMIC_REFERENCE = new AtomicStampedReference<String>("abc" , 0); public static void main(String []args) { for(int i = 0 ; i < 100 ; i++) { final int num = i; final int stamp = ATOMIC_REFERENCE.getStamp(); new Thread() { public void run(){ try { Thread.sleep(Math.abs((int)(Math.random() * 100))); }catch (InterruptedException e){ e.printStackTrace(); } if(ATOMIC_REFERENCE.compareAndSet("abc" , "abc2" , stamp , stamp + 1)){ System.out.println("我是线程:" + num + ",我获得了锁进行了对象修改!"); } } }.start(); } new Thread(){ public void run(){ int stamp=ATOMIC_REFERENCE.getStamp(); while(!ATOMIC_REFERENCE.compareAndSet("abc2", "abc" , stamp , stamp + 1)); System.out.println("已经改回为原始值!"); } }.start(); } }
总结:使用atomic包下的各种类来处理线程线程之间的竞争要比使用synchronized关键字要高效的多,尽量使用原子类。
相关文章推荐
- 【java总结】多线程进阶篇之locks包
- 【java总结】多线程进阶篇之任务执行
- Java——多线程总结及ThreadLocal、Volatile、synchronized、Atomic四个关键字
- 【java总结】多线程进阶篇之数据结构
- Java多线程知识点总结——进阶篇(一)之卖票程序
- 【java总结】多线程进阶篇之辅助类
- Java多线程知识点总结——进阶篇(三)之同步函数用的是哪一个锁问题
- Java【多线程知识总结(2)】调用setDaemon(true)变成后台线程
- Java 多线程总结
- Java多线程编程总结--新特征-条件变量
- Java【多线程知识总结(1)】用Thread类创建线程
- Java 多线程学习总结6
- Java的多线程编程模型5--从AtomicInteger开始
- JAVA多线程我的总结
- java笔记总结_07_多线程
- Java多线程 -- 深入理解JMM(Java内存模型) --(七)总结
- Java多线程编程总结笔记——一多线程基础知识
- Java多线程编程总结 链接
- Java多线程编程总结笔记——一多线程基础知识
- java 多线程精要总结