自旋锁:spinlock
是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环耗用CPU
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
public class SpinLockTest {
/**
* 自旋锁:
* 是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环耗用CPU
* 而在一个多核的机器中,多个线程是可以并行执行的。如果当后面请求锁的线程没拿到锁的时候,不挂起线程,而是继续占用处理器的执行时间,
* 让当前线程执行一个忙循环(自旋操作),
* 也就是不断在盯着持有锁的线程是否已经释放锁,那么这就是传说中的自旋锁了。
* @param args
*/
/**
* 1.6 版本后使用了自适应自旋锁:
* 自旋次数通常由前一次在同一个锁上的自旋时间及锁的拥有者的状态决定。如果线程【T1】自旋成功,自旋次数为17次,那么等到下一个线程【T2】自旋时,
* 也会默认认为【T2】自旋17次成功,
如果【T2】自旋了5次就成功了,那么此时这个自旋次数就会缩减到5次。
自适应自旋锁随着程序运行和性能监控信息,从而使得虚拟机可以预判出每个线程大约需要的自旋次数
* @param args
*/
public static void main(String[] args) {
SpinLockTest sl= new SpinLockTest();
// 给线程赋予AA名称
new Thread(()->{
sl.myLock();
try {
// 休眠5 秒
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sl.unMyLock();
},"AA").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(()-> {
sl.myLock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sl.unMyLock();
},"BB").start();
}
// AtomicReference 原子方式更新对象引用 ,保证多线程下操作该对象进行更新时,避免出现脏读,只要有一个线程改变 ,
//其他现场不会在改变该值
AtomicReference atomicReference = new AtomicReference<>();
// null 表示锁未被线程持有, atomicReference.compareAndSet(t,null); 线程的持有状态改变为null
public void myLock() {
Thread t=Thread.currentThread();
System.out.println(t.currentThread().getName()+ "come in");
while (!atomicReference.compareAndSet(null, t)) {
}
}
public void unMyLock() {
Thread t=Thread.currentThread();
atomicReference.compareAndSet(t,null);
System.out.println(t.currentThread().getName()+ "invoked unMyLock() ");
}
}