一. 手写自旋锁
自旋锁好处,循环比较获取直到成功为止,没有类似wait的阻塞
1. 实现步骤
通过CAS操作完成自旋锁,
T1线程先进来调用mylock方法自己持有锁5秒钟,
T2随后进来发现当前有线程持有锁,不是null,所以只能通过自旋等待,
直到T1释放锁后T2随后抢到线程资源
Java底层源码是这样实现自旋锁的
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
我们也可以模范其精华,先把获得锁和释放锁写出来,很容易,需要使用到前面的文章 解密CAS 中提到过atomicReference.compareAndSet()方法。
//原子引用线程
AtomicReference<Thread> atomicReference = new AtomicReference<>();
public void myLock() {
//获得锁
//当前线程
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName() + "\t myLock (●'◡'●)");
//只有当值比较交换完才会返回true,在取反才会退出循环
while (!atomicReference.compareAndSet(null, thread)){
}
}
public void myUnLock() {
//释放锁
//当前线程
Thread thread = Thread.currentThread();
//将当前线程置为null,释放锁
atomicReference.compareAndSet(thread, null);
System.out.println(Thread.currentThread().getName() + "\t myUnLock o(* ̄▽ ̄*)ブ");
}
测试
public static void main(String[] args) {
SpinLockDemo spinLockDemo = new SpinLockDemo();
new Thread(() -> {
//获得锁
spinLockDemo.myLock();
//睡 5秒
try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
//释放锁
spinLockDemo.myUnLock();
}, "T1").start();
//保证 T1线程先启动
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> {
//获得锁
spinLockDemo.myLock();
//释放锁
spinLockDemo.myUnLock();
}, "T2").start();
}
运行结果
大体描述一下执行过程
首先T1先去获得锁,在获得锁后,他需要等待5秒再去执行释放锁的方法,
而这时T2也去获得锁,但是CAS的过程中,发现锁不能被交换,也就是锁不能被获得,
只能老老实实的等待T1线程结束
等T1释放锁后,T2才能获得锁,然后在释放锁。