所谓⾃旋锁,就是尝试获取锁的线程不会⽴即阻塞,⽽是采⽤循环的⽅式去尝试获取。
⾃⼰在那⼉⼀直 循环获取,就像“⾃旋”⼀样。
这样的好处是减少线程切换的上下⽂开销,缺点是会消耗CPU。
CAS底层的getAndAddInt就是⾃旋锁思想。
//跟CAS类似,⼀直循环⽐较。
while (!atomicReference.compareAndSet(null, thread)) { }
详⻅SpinLockDemo。
package thread;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/** * 题⽬:实现⼀个⾃旋锁
* * ⾃旋锁好处:循环⽐较获取直到成功为⽌,没有类似wait的阻塞。
* * 通过CAS操作完成⾃旋锁,A线程先进来调⽤myLock⽅法⾃⼰持有锁5秒钟,
* * B随后进来后发现当前有线程持有锁,不是null,所以只能通过⾃选等待,直到A释放锁后B随后 抢到。
* */
public class SpinLockDemo {
//原⼦引⽤线程
AtomicReference<Thread> atomicReference = new AtomicReference<>();
// 上锁
public void myLock(){
// 获取当前线程
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName()+"\t"+"com in...");
// 如果原来是没有线程占用,当前线程占用上
// 如果占用成功,则跳出循环
// 如果没有占用成功,则一直循环等待
while(!atomicReference.compareAndSet(null, thread)){
}
}
// 解锁
public void myUnLock(){
// 获取当前线程
Thread thread = Thread.currentThread();
// 如果当前线程是被自己占用的,则释放
atomicReference.compareAndSet(thread, null);
System.out.println(Thread.currentThread().getName()+"\t"+" unlock...");
}
public static void main(String[] args) {
SpinLockDemo spinLockDemo = new SpinLockDemo();
// AA
new Thread(()->{
spinLockDemo.myLock();
try {
TimeUnit.SECONDS.sleep(5);
}
catch (InterruptedException e) {
e.printStackTrace();
}
spinLockDemo.myUnLock();
}, "AA").start();
try {
TimeUnit.SECONDS.sleep(1);
}
catch (InterruptedException e) {
e.printStackTrace();
}
// BB
new Thread(()->{
spinLockDemo.myLock();
try {
TimeUnit.SECONDS.sleep(1);
}
catch (InterruptedException e) {
e.printStackTrace();
}
spinLockDemo.myUnLock();
}, "BB").start();
}
}