java并发编程(7)-- 线程 自旋锁_java

所谓⾃旋锁,就是尝试获取锁的线程不会⽴即阻塞,⽽是采⽤循环的⽅式去尝试获取。

⾃⼰在那⼉⼀直 循环获取,就像“⾃旋”⼀样。

这样的好处是减少线程切换的上下⽂开销,缺点是会消耗CPU。

CAS底层的getAndAddInt就是⾃旋锁思想。

//跟CAS类似,⼀直循环⽐较。

while (!atomicReference.compareAndSet(null, thread)) { }

java并发编程(7)-- 线程 自旋锁_跳出循环_02

详⻅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();

}
}


java并发编程(7)-- 线程 自旋锁_跳出循环_03