本文最后更新于 493 天前,其中的信息可能已经有所发展或是发生改变。
注意:Wating的原因
Compare And Set,无锁优化,自旋
CPU原语支持,运行期间不被打断
cas(V,Expected,NewValue)
if V==E
V=New
otherwise
try again or fail
ABA问题
线程1读取的共享变量为A,进行CAS操作,期间其他线程将该变量修改为B后,又修改为A。CAS认为此变量符合预期。
解决方式:加版本号
java.util.concurrent.atomic包下都是CAS原理
atomicLong在并发量较低的环境下,线程冲突的概率比较小,自旋的次数不会很多。但是,高并发环境下,N个线程同时进行自旋操作,会出现大量失败并不断自旋的情况,此时AtomicLong的自旋会成为瓶颈。
AtomicLong中有个内部变量value保存着实际的long值,所有的操作都是针对该变量进行。也就是说,高并发环境下,value变量其实是一个热点,也就是N个线程竞争一个热点。
LongAdder的基本思路就是分散热点,将value值分散到一个数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,这样热点就被分散了,冲突的概率就小很多。如果要获取真正的long值,只要将各个槽中的变量值累加返回。
这种做法有没有似曾相识的感觉?没错,ConcurrentHashMap中的“分段锁”其实就是类似的思路。
需要手动lock和unlock,一般将unlock写到finally里。synchronized遇到异常会自动释放锁,而ReentrantLock不会。
底层为CAS加等待队列
trylock:尝试获取锁
boolean locked = false;
try {
locked=lock.tryLock(time:5,TimeUnit.SECONDS);
System.out.println("m2..."+Locked);
} catch(InterruptedException e){
e.printStackTrace();
} finally {
if(locked) lock. unlock();
}
lockInterruptibly允许在等待时由其它线程调用等待线程的Thread.interrupt方法来中断等待线程的等待而直接返回,这时不用获取锁,而会抛出一个InterruptedException。
公平锁
参数为true表示为公平锁,请求锁的线程在等待队列里FIFO
ReentrantLock lock=new ReentrantLock(true);
CountDownLatch countDownLatch = new CountDownLatch;
countDownLatch.countDown();
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}