概念和意义
尝试获取锁的线程不会立即阻塞(no wait),而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环消耗cpu
unsafe中的源码
//unsafe.getAndAddInt putlic final int getAndAddInt(Object var1,long var2, int var4){ int var5; do{ var5 = this.getVolatile(var1,var2); }while(!this.compareAndSwapInt(var1,var2,var5,var5+var4)); return var5; }
var1:对象
var2:偏移地址
var5:通过var1和var2得到内存中的变量
会持续获得内存var2中的变量,如果取得的值被修改了,就会重复这一步骤,直到拿到正确的值,然后将值设置为var5+var4。
使用AtomicReference模拟自旋锁
public class SpinLockTest { AtomicReference<Thread> atomicReference = new AtomicReference<>(); // 自定义自旋锁 public void myLock(){ Thread thread = Thread.currentThread(); System.out.println(Thread.currentThread().getName()+"等待拿锁"); while(!atomicReference.compareAndSet(null,thread)){ } System.out.println(Thread.currentThread().getName()+"拿到了"); } // 自定义解锁 public void myUnlock(){ Thread thread = Thread.currentThread(); System.out.println(Thread.currentThread().getName()+"释放了锁"); atomicReference.compareAndSet(thread,null); } public static void main(String[] args) { SpinLockTest spin = new SpinLockTest(); // 线程AA拿锁5秒后释放 new Thread(()->{ spin.myLock(); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } spin.myUnlock(); },"AA").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } // 线程BB尝试拿锁,然后释放 new Thread(()->{ spin.myLock(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } spin.myUnlock(); },"BB").start(); } }