java自旋锁Demo+原理

自旋一词来源于CAS,即compareandSet(比较和交换),CAS实现基础应在原子引用或者操作原子Atomic类型之上,意思就是线程通过不断循环的方式来获取锁,

若读完不懂或没读就不懂,请复习JMM内存模型+volatile+java.util.concurrent.Atomic再来.

package com.reentralock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 自旋锁 线程a调lock方法 自己持有锁5s,b在5s内不断尝试获取锁 
 * 
 * 自旋的基础是Atomic,所以一定要用到原子引用
 */
public class SpinLock {

	AtomicReference<Thread> reference = new AtomicReference<>();//此时构造方法未传入值,此时原子线程默认是null
	
	public void myLock(){
		Thread thread = Thread.currentThread();
		System.out.println(Thread.currentThread().getName()+"\t come in");
		
		//自旋的精髓是循环
		while(!reference.compareAndSet(null, thread)){//
			System.out.println(Thread.currentThread().getName()+"\t 循环尝试获取锁");
		}
		
	}
	
	public void myUnLock(){
		Thread thread = Thread.currentThread();
		System.out.println(Thread.currentThread().getName()+"\t unlock");
		reference.compareAndSet(thread, null);//原子操作+期望值吻合+释放
		
	}
	public static void main(String[] args) {
		SpinLock spinLock =new SpinLock();
		
		new Thread(()->{
			spinLock.myLock();//aa获取锁
			try {
				TimeUnit.SECONDS.sleep(5);//aa持有锁5s
			} catch (Exception e) {
				e.printStackTrace();
			}
			spinLock.myUnLock();//aa释放锁
		}, "aa").start();
		
		try {
			TimeUnit.SECONDS.sleep(1);//保证线程aa先获取到锁
		} catch (Exception e) {
			e.printStackTrace();
		}
		new Thread(()->{
			spinLock.myLock();//bb获取锁
            System.out.println("bb终于得到锁了");
			spinLock.myUnLock();//bb释放锁
		}, "bb").start();
	}
}

当aa线程获取主内存的共享变量reference的副本到自己的工作内存且reference=null时,null为aa线程的期望值,若为null,aa线程在自己的工作内存中将reference=null改成reference=aa线程,aa线程执行时间为5s(在5s过程中,bb线程启动),5s后aa线程调unlock方法将reference=aa改为reference=null,并将reference=null写回主内存中;bb线程在aa线程启动的1s后,不断获取主存中reference的值,但在aa线程没执行完之前,主内存的reference始终=aa线程,故bb执行while方法不断循环获取主内存的reference,直到aa线程执行5s完毕,主存的reference=null;线程bb如愿以偿的获取到了锁,打印了“bb终于得到锁了”这句话,后释放了锁,将reference恢复到初始值:reference=null,也就是最初的代码AtomicReference<Thread> reference = new AtomicReference<>();。

总结:自旋锁其实就是线程aa获取到锁,bb线程在获取锁的时候不是处于阻塞状态在等待队列中一直等,而是不断循环的获取锁,但是如果说aa执行时间特别长,bb还是在不断获取,因为每次获取都需要一点内存来执行,这样会大量耗费cpu的资源,影响性能,应根据情况使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章