这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战
ps:昨天又是一样的七夕,呜呜呜~~~,大家呢?
学习学习!!!
介绍
-
一种有名的无锁算法,不使用锁的情况下实现多线程间变量的同步
-
尝试获取锁的线程不会立即阻塞,而是反复尝试的去获得锁,好处是减少上下文切换的消耗,缺点是消耗cpu
-
是一种基于CAS的锁,此时比较并交换的类型变成了线程(Thread)
先来到该方法下,这就是一个自旋锁的实现思想
AtomicInteger - > getAndIncrement -> unsafe.getAndAddInt
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;
自旋锁Demo
1.使用了AtomicReference类实现原子引用线程,这里我们可以把AtomicReference当成一个容器,丢进这个容器的类型就可以实现原子操作,例如这边是Thread类型可以实现原子操作
2.刚开始的时候atomicReference没有Thread类型的数据,所以为null,那么在上锁的时候判断
while(!atomicReference.compareAndSet(null,curThread)){ }
此时期望值为null实际值为空,那么实际值就被修改为curThread(当前线程),获取锁成功,而BBB线在获取锁的时候期望值为空实际值却是AAA线程,暂时无法获得锁,就一直在while中循环尝试,直到AAA线程释放锁
3.unlock方法会比较是否为当前线程,如果是当前线程的话就释放锁(就是把atomicReference中的thread变成空,这样其他线程就能获取锁了)
public class SpinLockDemo {
//原子引用线程
AtomicReference<Thread> atomicReference = new AtomicReference<>();
public static void main(String[] args) throws InterruptedException {
SpinLockDemo spinLockDemo = new SpinLockDemo();
new Thread(()->{
spinLockDemo.myLock();
try { Thread.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
spinLockDemo.unlock();
},"AAA").start();
TimeUnit.SECONDS.sleep(1);//为了让A线程先获得cpu的时间片
new Thread(()->{
spinLockDemo.myLock();
spinLockDemo.unlock();
},"BBB").start();
}
public void myLock(){
Thread curThread = Thread.currentThread();
System.out.println(curThread.getName()+"\t com in ~~~");
while(!atomicReference.compareAndSet(null,curThread)){
}
}
public void unlock(){
Thread curThread = new Thread().currentThread();
atomicReference.compareAndSet(curThread,null);
System.out.println(curThread.getName()+"\t 线程释放锁 ~~~");
}
}
运行结果:
AAA com in ~~~
AAA 线程释放锁 ~~~
BBB com in ~~~
BBB 线程释放锁 ~~~