手写自旋锁
- 循环比较获取直到成功为止,没有类似于wait的阻塞
- 通过CAS操作完成自旋锁,A线程先进来调用myLock方法自己持有锁5秒,B随后进来发现当前有线程持有锁,不是null,所以只能通过自旋等待,直到A释放锁后B随后抢到
public class SpinLockDemo {
//现在的泛型装的是Thread,原子引用线程
AtomicReference<Thread> atomicReference = new AtomicReference<>();
/**
* 加锁方法
*/
public void addLock() {
Thread thread = Thread.currentThread();
System.out.println("threadName = " + thread.getName() + "\t come in ");
//开始利用CAS自旋,期望值是null,更新为当前线程。如果是null,更新为当前线程,否则自旋
while (!atomicReference.compareAndSet(null, thread)) {
System.out.println("线程名 " + thread.getName() + " ,正在自旋,不断通过CAS尝试获取锁");
}
}
/**
* 解锁方法
*/
public void cancelLock() {
Thread thread = Thread.currentThread();
System.out.println("threadName = " + thread.getName() + "\t come out ");
//自己用完了后,把atomicReference变成null
atomicReference.compareAndSet(thread, null);
System.out.println("threadName = " + thread.getName() + "\t 已完成解锁 ");
}
}
创建两个线程 t1,t2 分别调用加锁和解锁的方法
public static void main(String[] args) {
SpinLockDemo spinLockDemo = new SpinLockDemo();
new Thread(() -> {
//加锁
spinLockDemo.addLock();
System.out.println("t1线程 执行业务逻辑--> 赚钱赚钱赚钱赚钱赚钱赚钱赚钱操作");
try {
//1毫秒的时间内都在赚钱
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//解锁
spinLockDemo.cancelLock();
}, "t1").start();
new Thread(() -> {
//加锁
spinLockDemo.addLock();
System.out.println("t2线程 执行业务逻辑--> 把钱存进银行的操作");
//解锁
spinLockDemo.cancelLock();
}, "t2").start();
}
上述代码执行结果如下
threadName = t1 come in
t1线程 执行业务逻辑--> 赚钱赚钱赚钱赚钱赚钱赚钱赚钱操作
threadName = t2 come in
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
threadName = t1 come out
线程名 t2 ,正在自旋,不断通过CAS尝试获取锁
threadName = t1 已完成解锁
t2线程 执行业务逻辑--> 把钱存进银行的操作
threadName = t2 come out
threadName = t2 已完成解锁
由此可知CAS的方法加锁会频繁自旋,占用CPU,过于浪费系统资源
将t1线程的睡眠时间替换成100ms
TimeUnit.MILLISECONDS.sleep(100);
查看cpu的使用情况如下: