锁是一种悲观策略,总是觉得会出问题,所以小心翼翼地操作。
无锁是一种乐观策略,总是假设不会出现问题,如果出现问题,那就重新操作。无锁一般使用CAS作为策略。
比较交换CAS:
CAS算法包括三个参数:需要更新的变量,预期值,更新值。只有当需要更新的值等于预期值时,说明其他线程没有对它进行操作,使需要更新值等于更新值。
在java.util.concurrent.atomic中,实现了很多无锁的类型:
用AtomicInteger写个小例子:
public class demo implements Runnable{ static AtomicInteger ai=new AtomicInteger(); public static void main(String[] args) throws InterruptedException { ExecutorService es=Executors.newFixedThreadPool(10); for(int i=0;i<10;i++) { es.submit(new demo()); } Thread.sleep(1000); System.out.println(ai); } public void run() { for(int i=0;i<100;i++) { ai.incrementAndGet(); } } }
没有加锁的情况下,输出结果为1000,AtomicXX的操作都是具有原子性的,具体方法可以自己看API。
我们接下来看一下incrementAndGet()方法:
public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } }
如上面对CAS算法的描述一样,不断尝试直到成功,进入compareAndSet():
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
调用了unsafe类的compareAndSwapInt,只需要知道他的大概意思就行,通过字段偏移量找到位置,通过期望值与待更新值的对比决定要不要更新。