无锁
一、概述
无锁是处理并发的一种乐观策略,它会假设对资源的访问是没有冲突的。既然没有冲突自然不需要等待,所以所有的线程都可以在不停顿的状态下执行。那遇到冲突怎么办?接下来请看,无锁绝招“CAS”即比较交换术。
二、CAS原理
CAS即Compare and swap.其算法过程是这样的:它有三个参数:
1.V表示要更新的变量
2.E表示期望值
3.N表示新值
仅当V等于E时,才会将V设为N。如果V和N不同,则说明有其他线程做了更新,则该线程什么都不做。当多个线程同时使用CAS进行变量操作时,只有一个会更新成功,其余都会失败。失败的线程不会被挂起,而是进行重试。
三、无锁的线程安全整数:AtomicInteger
AtomicInteger主要方法如下(对于其他无锁线程安全类,其方法类似):
public final int get() //取得当前值 public final void set(int newValue) //设置当前值 public final int getAndset(int newValue) //设置新值返回旧值 public final boolean compareAndSet(int except,int u) //如果当前值为except则设为u public final int getAndIncrement() //当前值加1返回旧值 public final int getAndDecrement() public final int getAndAdd(int delta) public final int incrementAndGet() public final int decrementAndGet() public final int addAndGet()
就AtomicInteger核心字段:
private volatile int value; //代表AtomicInteger当前的值
private static final long valueOffset; //value字段的偏移量
AtomicInteger的使用示例:
public class AutomicIntegerDemo { static AtomicInteger i=new AtomicInteger(); public static class addThread implements Runnable{ @Override public void run() { for(int j=0;j<1000;j++){ i.incrementAndGet(); } } } public static void main(String[] args) throws InterruptedException { Thread[] ts=new Thread[10]; for(int j=0;j<10;j++){ ts[j]=new Thread(new addThread()); } for(int j=0;j<10;j++) ts[j].start(); for (int j=0;j<10;j++) ts[j].join(); System.out.println(i); } }
相比使用锁,使用无锁会有更好的性能。
四、CAS算法逻辑上瑕疵及解决办法:AtomicStampedReference
CAS算法逻辑上的瑕疵:当你获得对象当前数据后,在准备修改为新值前,对象的值被其他对象连续修改了两次,而经过这两次修改后,对象的值又恢复到旧值。这样,当前线程就无法判断该值是否被修改过。也就是说你修改的对象数值没有过程状态信息。
AtomicStampedReference内部不仅维护了对象值还维护了一个状态值。
五、无锁数组
当前可用的原子数组有:AtomicIntegerArray,AtomicLongArray和AtomicReferenceArray
public class AtomicIntegerArrayDemo { static AtomicIntegerArray array=new AtomicIntegerArray(10); public static class addThread implements Runnable{ @Override public void run() { for (int j=0;j<1000;j++){ array.getAndIncrement(j%array.length()); } } } public static void main(String[] args) throws InterruptedException { Thread[] ts=new Thread[10]; for (int j=0;j<10;j++){ ts[j]=new Thread(new addThread()); } for (int j=0;j<10;j++) ts[j].start(); for (int j=0;j<10;j++) ts[j].join(); System.out.println(array); } }
六、让普通变量也享受原子操作:AtomicIntegerFieldUpdater
public class AtomicIntegerFieldUpdaterDemon { public static class Candidate{ int id; volatile int score; } public final static AtomicIntegerFieldUpdater<Candidate> scoreUpdater= AtomicIntegerFieldUpdater.newUpdater(Candidate.class,"score"); public static AtomicInteger checkScore=new AtomicInteger(0); //用于检测 public static void main(String[] args) throws InterruptedException { final Candidate candidate=new Candidate(); Thread[] threads=new Thread[1000]; for (int i=0;i<1000;i++){ threads[i]=new Thread(){ public void run(){ if (Math.random()>0.4){ scoreUpdater.incrementAndGet(candidate); checkScore.incrementAndGet(); } } }; threads[i].start(); } for (int i=0;i<1000;i++) threads[i].join(); System.out.println("score="+candidate.score); System.out.println("checkScore="+checkScore); } }
注意事项:
1.Updater只能修改可见范围内的变量。
2.变量必须是volatile
3.变量不能是static的