Java锁之自旋锁

自旋锁是指定尝试获取锁的线程不会立即堵塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上线文切换的消耗,缺点就是循环会消耗 CPU。

手写一个自旋锁 

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
 * 手写一个自旋锁
 * @author kavito
 *
 */
public class SpinLock {
	
	//原子引用类
	AtomicReference atomic=new AtomicReference<>();
	
	public void myLock(){
		System.out.println(Thread.currentThread().getName()+"\t进来");
		Thread thread=Thread.currentThread();
		while(!(atomic.compareAndSet(null, thread))){
			System.out.println(Thread.currentThread().getName()+"\t尝试加锁....");
		}
		System.out.println(Thread.currentThread().getName()+"\t加锁成功!");
	}
	
	public void myUnLock(){	
		Thread thread=Thread.currentThread();
		//释放锁
		atomic.compareAndSet(thread, null);
		System.out.println(Thread.currentThread().getName()+"\t解锁完毕!");	
	}
	
	public static void main(String[] args) {
		SpinLock spinLock=new SpinLock();
		new Thread(()->{
			spinLock.myLock();
			//睡眠2秒,让t2线程进去加锁
			try { TimeUnit.SECONDS.sleep(2); } catch (Exception e) { e.printStackTrace(); }
			spinLock.myUnLock();
		},"t1线程").start();		
		//先让t1线程加锁
		try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); }
		new Thread(()->{
			spinLock.myLock();
			//模拟任务耗时
			try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); }
			spinLock.myUnLock();	
		},"t2线程").start();
	}

}
 
  

运行效果: 

Java锁之自旋锁_第1张图片  Java锁之自旋锁_第2张图片

1、t1线程先进来,相对于原子引用对象atomic,预期值是null,实际atomic对象也是null,比较成功,atomic修改为t1线程对象thread,atomic.compareAndSet(null, thread)返回true,整体取反返回false,跳出循环,t1线程加锁成功。t1线程暂停2秒,t2进来了,由于t1线程还没释放锁,atomic里面实际的值还是t1线程对象,通过atomic.compareAndSet(null, thread)想讲t1对象更换为t2对象来获取锁,预期的值是null,实际值是t1线程对象,atomic.compareAndSet(null, thread)返回false,整体取反返回true,
进了while循环,一直循环尝试加锁,直到t1线程释放锁。

2、t1线程sleep时间到了,spinLockDemo.myUnlock()释放锁atomic.compareAndSet(thread, null),此时atomic的实际值是null,t1线程执行完毕。之前t2线程一直循环等待atomic的值为null,条件终于满足,t2线程atomic.compareAndSet(null, thread)加锁成功,返回true,取反为false,跳出while循环,spinLockDemo.myUnlock(),解锁,直到代码执行完毕!

你可能感兴趣的:(多线程)