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的資源,影響性能,應根據情況使用。

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