一、锁的劣势
锁定后如果未释放,再次请求锁时会造成阻塞,多线程调度通常遇到阻塞会进行上下文切换,造成更多的开销。
在挂起与恢复线程等过程中存在着很大的开销,并且通常存在着较长时间的中断。
锁可能导致优先级反转,即使较高优先级的线程可以抢先执行,但仍然需要等待锁被释放,从而导致它的优先级会降至低优先级线程的级别。
处理器填写了一些特殊指令,例如:比较并交换、关联加载/条件存储。
1 比较并交换
CAS的含义是:“我认为V的值应该为A,如果是,那么将V的值更新为B,否则不需要修改告诉V的值实际为多少”。CAS是一项乐观锁技术。
模拟CAS操作例子:
[java]view plaincopy
@ ThreadSafe
publicclassSimulatedCAS {
@ GuardeBy("this")privateintvalue ;
publicsynchronizedintget(){
returnvalue ;
}
publicsynchronizedintcompareAndSwap(intexpectedValue,intnewValue){
intoldValue = value ;
if(oldValue == expectedValue)
value = newValue;
returnoldValue;
}
publicsynchronizedbooleancompareAndSet(intexpectedValue,intnewValue){
return(expectedValue == compareAndSwap(expectedValue, newValue));
}
}
2 非阻塞的计数器
基于CAS实现的非阻塞计数器
[java]view plaincopy
@ ThreadSafe
publicclassCasCounter {
privateSimulatedCAS value ;
publicintgetValue(){
returnvalue .get();
}
publicintincrement(){
intv;
do{
v = value .get();
}while(v != value .compareAndSwap(v, v +1));
returnv +1;
}
}
CAS的主要缺点是:它将使调度者处理竞争问题(通过重试、回退、放弃),而在使用锁中能自动处理竞争问题(线程在获得锁之前将一直阻塞)。
3 JVM对CAS的支持
[java]view plaincopy
java.util.concurrent.atomic 类的小工具包,支持在单个变量上解除锁的线程安全编程。
AtomicBoolean 可以用原子方式更新的boolean值。
AtomicInteger 可以用原子方式更新的int值。
AtomicIntegerArray 可以用原子方式更新其元素的int数组。
AtomicIntegerFieldUpdater 基于反射的实用工具,可以对指定类的指定volatileint字段进行原子更新。
AtomicLong 可以用原子方式更新的long值。
AtomicLongArray 可以用原子方式更新其元素的long数组。
AtomicLongFieldUpdater 基于反射的实用工具,可以对指定类的指定volatilelong字段进行原子更新。
AtomicMarkableReference AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。
AtomicReference 可以用原子方式更新的对象引用。
AtomicReferenceArray 可以用原子方式更新其元素的对象引用数组。
AtomicReferenceFieldUpdater 基于反射的实用工具,可以对指定类的指定volatile字段进行原子更新。
AtomicStampedReference AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。
1 原子变量是一种“更好的volatile”
通过CAS来维持包含多个变量的不变性条件例子:
[java]view plaincopy
importjava.util.concurrent.atomic.AtomicReference;
publicclassCasNumberRange {
privatestaticclassIntPair{
finalintlower ;// 不变性条件: lower <= upper
finalintupper ;
publicIntPair(intlower,intupper) {
this.lower = lower;
this.upper = upper;
}
}
privatefinalAtomicReference values =
newAtomicReference(newIntPair(0,0));
publicintgetLower(){
returnvalues .get(). lower;
}
publicintgetUpper(){
returnvalues .get(). upper;
}
publicvoidsetLower(inti){
while(true){
IntPair oldv = values .get();
if(i > oldv.upper ){
thrownewIllegalArgumentException("Cant't set lower to "+ i +" > upper");
}
IntPair newv =newIntPair(i, oldv.upper );
if(values .compareAndSet(oldv, newv)){
return;
}
}
}
// 对setUpper采用类似的方法
}
2 性能比较:锁与原子变量
使用ReentrantLock、AtomicInteger、ThreadLocal比较,通常情况下效率排序是ThreadLocal > AtomicInteger > ReentrantLock。
1 非阻塞的栈
[java]view plaincopy
importjava.util.concurrent.atomic.AtomicReference;
publicclassConcurrentStack {
privateAtomicReference> top =newAtomicReference>();
publicvoidpush(E item){
Node newHead =newNode(item);
Node oldHead;
do{
oldHead = top .get();
newHead. next = oldHead;
}while(!top .compareAndSet(oldHead, newHead));
}
publicE pop(){
Node oldHead;
Node newHead;
do{
oldHead = top .get();
if(oldHead ==null) {
returnnull;
}
newHead = oldHead. next ;
}while(!top .compareAndSet(oldHead, newHead));
returnoldHead.item ;
}
privatestaticclassNode{
publicfinalE item;
publicNode next ;
publicNode(E item){
this.item = item;
}
}
}
2 非阻塞的链表
CAS基本使用模式:在更新某个值时存在不确定性,以及在更新失败时重新尝试。
[java]view plaincopy
importjava.util.concurrent.atomic.AtomicReference;
@ ThreadSafe
publicclassLinkedQueue {
privatestaticclassNode{
finalE item;
finalAtomicReference> next;
publicNode(E item, Node next){
this.item = item;
this.next =newAtomicReference>(next);
}
}
privatefinalNode dummy =newNode(null,null);
privatefinalAtomicReference> head =
newAtomicReference>(dummy);
privatefinalAtomicReference> tail =
newAtomicReference>(dummy);
publicbooleanput(E item){
Node newNode =newNode(item,null);
while(true){
Node curTail = tail.get();
Node tailNext = curTail.next.get();
if(curTail == tail.get()){
if(tailNext !=null){
// 队列处于中间状态,推进尾节点
tail.compareAndSet(curTail, tailNext);
}else{
// 处于稳定状态, 尝试插入新节点
if(curTail.next.compareAndSet(null, newNode)){
// 插入操作成功,尝试推进尾节点
tail.compareAndSet(curTail, tailNext);
returntrue;
}
}
}
}
}
}
3 原子的域更新器
原子的域更新器类表示有volatile域的一种基于反射的“视图”,从而能够在已有的volatile域上使用CAS
[java]view plaincopy
privatestaticclassNode{
privatefinalE item;
privatevolatileNode next;
publicNode(E item){
this.item = item;
}
}
privatestaticAtomicReferenceFieldUpdater nextUpdater
= AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class,"next");
4 ABA问题
处理V的值首先由A变成B,再由B变成A的问题。
好了同学们,我能介绍的也都全部介绍完给你们了,如果下获得更多JAVA教学资源,可以选择来我们这里共同交流,群:240448376,很多大神在这里切磋学习,不懂可以直接问,晚上还有大牛免费直播教学。
注:加群要求
1、具有一定工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加,有些应届生和实习生也可以加。
2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加。
3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加。
4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加。
5.阿里Java高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!
PS:现在主要讲解的内容是(反射原理、枚举原理与应用、注解原理、常用设计模式、正规表达式高级应用、JAVA操作Office原理详解、JAVA图像处理技术,等多个知识点的详解和实战)
6.小号或者小白之类加群一律不给过,谢谢。
最后,每一位读到这里的网友,感谢你们能耐心地看完。觉得对你有帮助可以给个喜欢!希望在成为一名更优秀的Java程序员的道路上,我们可以一起学习、一起进步