实例讲解Java 自旋锁
一直以来不是怎么清楚自旋锁,最近有点时间,好好的学习了一下;
所谓的自旋锁在我的理解就是多个线程在尝试获取锁的时候,其中一个线程获取锁之后,其他的线程都处在一直尝试获取锁的状态,不会阻塞!!!那么什么叫做一直尝试获取锁呢?就是一个循环,比较经典的是AtomicInteger中的一个updateAndGet方法,下图所示(当然也可以直接看unsafe类中的getAndAddInt等类似方法);
我们可以看出在while循环中使用CAS去尝试更新一个变量,如果更新失败,就会一直在这个循环中一直在尝试;成功的话,就可以到最后的return语句;
由此我们可以大概知道如果自旋的线程过多,那么CPU的资源就会被大量消耗!!!
顺便提一个东西叫做原子引用,官方提供了AtomicInteger,AtomicBoolean等原子类,那么如果我们自己定义的类也需要有原子性怎么办呢?所以官方提供了一个AtomicReference类,可以将我们自己定义的类封装一下,就成了我们自己的原子类,例如AtomicReference
栗子:
packageTestMain;
importlombok.extern.slf4j.Slf4j;
importjava.util.concurrent.TimeUnit;
importjava.util.concurrent.atomic.AtomicReference;
@Slf4j
publicclassTestMain80{
//一个Thread类的原子引用
AtomicReferenceatomicReference=newAtomicReference<>();
//加锁的方法
publicvoidmyLock(){
ThreadcurrentThread=Thread.currentThread();
log.info("myLock--Thread:{}",currentThread.getName());
//这个就是自旋锁的核心,利用CAS比较当前原子引用中是否为null,如果是null,就把当前线程A放到里面去,
//此时线程B再到这里,那么就会CAS失败,一直在while循环中
while(!atomicReference.compareAndSet(null,currentThread)){
}
}
//解锁的方法
publicvoidmyUnlock(){
ThreadcurrentThread=Thread.currentThread();
//CAS比较原子引用中是不是线程A,是的话就更新为null,此时在上面while中一直在自旋的线程B就可以跳出来了
atomicReference.compareAndSet(currentThread,null);
log.info("myUnlock--Thread:{}",currentThread.getName());
}
publicstaticvoidmain(String[]args){
TestMain80testMain80=newTestMain80();
//线程A,首先加锁,然后等3秒中,然后释放锁
newThread(()->{
testMain80.myLock();
try{
TimeUnit.SECONDS.sleep(3);
}catch(InterruptedExceptione){
e.printStackTrace();
}
testMain80.myUnlock();
},"A").start();
//主线程等1秒,保证A线程先执行
try{
TimeUnit.SECONDS.sleep(1);
}catch(InterruptedExceptione){
e.printStackTrace();
}
//线程B,加锁再释放锁
newThread(()->{
testMain80.myLock();
testMain80.myUnlock();
},"B").start();
}
}
上面的就是一个自旋锁的栗子,执行结果中首先是执行A线程的myLock方法,获取锁成功,之后的B线程虽然也会执行mylock方法,但是会在while循环中一直阻塞,直到线程A调用了myUnlock方法释放锁,最后两行才会打印出来;
以上就是实例讲解Java自旋锁的详细内容,更多关于Java自旋锁的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。