赞
踩
多线程下使用原子类来保证线程安全
public class AtomicIntegerTest {
AtomicInteger atomicInteger = new AtomicInteger(0);
public int getNum(){
return atomicInteger.get();
}
public void addNum(){
atomicInteger.getAndIncrement();
}
}
volatile能解决多线程并发安全中的可见性问题,但是不能解决原子性问题。
atomic原子类通过CAS+volatile来保证并发安全。CAS保证原子性,volatile保证原子性。
原子类位于java.util.concurrent.atomic包下面。可以分为以下几类,基本类型的原子类,数组类型的原子类,引用类型的原子类和对象的属性修改原子类四类。
AtomicBoolean, AtomicInteger, AtomicLong
常用的API:
获取值,自增,自减,CAS
使用举例:
public class AtomicIntegerDemo { public static final int SIZE = 50; public static void main(String[] args) throws InterruptedException { MyNumber myNumber = new MyNumber(); CountDownLatch countDownLatch = new CountDownLatch(SIZE); for (int i = 1; i <=SIZE; i++) { new Thread(() -> { try { for (int j = 1; j <=1000; j++) { myNumber.addPlusPlus(); } } finally { countDownLatch.countDown(); } },String.valueOf(i)).start(); } //等待上面50个线程全部计算完成后,再去获得最终值 //暂停几秒钟线程 //try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.await(); System.out.println(Thread.currentThread().getName()+"\t"+"result: "+myNumber.atomicInteger.get()); } }
补充:CountDownLatch计数器,可以使一个或多个线程等待其他线程执行完毕后再执行。
CountDownLatch定义了一个计数器和阻塞队列,当计数器减为0就唤醒阻塞队列中的线程。使用await()方法主动将当前线程阻塞(放入阻塞队列中)
AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray
常用的API
getAndSet(int i, int newValue)
getAndIncrement(int i)
getAndAdd(int i, int delta)
AtomicReference
原子引用类
AtomicStampedReference
原子邮戳(版本号)引用类,携带版本号的的原子引用。
AtomicMarkableReference
原子标记引用类,带标记(将版本号简化为true,false的标记)的原子引用。
常用API
public boolean isMarked();
public boolean compareAndSet(V expectedReference,
V newReference,
boolean expectedMark,
boolean newMark)
AtomicIntegerFiledUpdater, AtomicLongFiledUpdater, AtomicReferenceFiledUpdater
基于反射实现的,可以对volatile属性进行更新。因此需要更新的属性必须用volatile修饰。(volatile重要用法)
常用的API
static AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,String fieldName)
public int getAndIncrement(T obj)
static AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass,Class<W> vclass,String fieldName)//如果是引用属性,需要传入引用属性的字节码对象
举例: AtomicIntegerFiledUpdater
class BankAccount//资源类 { String bankName = "CCB"; //更新的对象属性必须使用 public volatile 修饰符。 public volatile int money = 0;//钱数 public void add() { money++; } //因为对象的属性修改类型原子类都是抽象类,所以每次使用都必须 // 使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。 AtomicIntegerFieldUpdater<BankAccount> fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(BankAccount.class,"money"); //不加synchronized,保证高性能原子性,局部微创小手术 public void transMoney(BankAccount bankAccount) { fieldUpdater.getAndIncrement(bankAccount); } }
举例: AtomicReferenceFiledUpdater
class MyVar //资源类 { public volatile Boolean isInit = Boolean.FALSE; AtomicReferenceFieldUpdater<MyVar,Boolean> referenceFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(MyVar.class,Boolean.class,"isInit"); public void init(MyVar myVar) { if (referenceFieldUpdater.compareAndSet(myVar,Boolean.FALSE,Boolean.TRUE)) { System.out.println(Thread.currentThread().getName()+"\t"+"----- start init,need 2 seconds"); //暂停几秒钟线程 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"\t"+"----- over init"); }else{ System.out.println(Thread.currentThread().getName()+"\t"+"----- 已经有线程在进行初始化工作。。。。。"); } } }
在高并发的情况下,使用Atomic原子类会导致线程竞争的时候CAS操作自旋消耗CPU的性能,这个时候用LongAdder性能更好,代价是空间消耗更多,以空间换时间。
LongAdder只能加减法,且从0开始。
LongAccumulator更强大,可以自定义运算。
在低并发无竞争的情况下跟AtomicLong一样,对同一个base操作。
当高并发的情况下:
LongAdder的核心思想就是以空间换时间,分散热点。在Atomic原子类的基础上将value值分散到多个cell中去(cell数组),不同的线程会命中不同的cell,每个线程对自己对应的cell进行操作,减少冲突从而减少CAS自旋。最后将各个celll中的变量累加返回即可。
常用的API
示例:
public class LongAdderAPIDemo { public static void main(String[] args) { LongAdder longAdder = new LongAdder(); longAdder.increment(); longAdder.increment(); longAdder.increment(); System.out.println(longAdder.sum()); LongAccumulator longAccumulator = new LongAccumulator(new LongBinaryOperator() { @Override public long applyAsLong(long left, long right) { return left + right; } },0); longAccumulator.accumulate(1);//1 longAccumulator.accumulate(3);//4 System.out.println(longAccumulator.get()); } }
AtomicLong: 原理CAS+自旋+volatile。进行计数,能够保证并发安全。在高并发下,性能急剧下降,自旋操作影响性能。
LongAdder: 原理CAS+Base+Cell+volatile。进行计数,能够保证并发安全。在高并发下,性能也很好。但是空间消耗略大。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。