天天看點

synchronized實作synchronize的鎖更新鎖:隻能更新,不能降級

實作

  • 非靜态方法的代碼塊

按照Hotspot的實作來看,是在這個對象的對象頭位置(64位,前兩位 ##mark word)記錄了這個對象鎖的狀态。

public synchronized void m1() { 
		System.out.println(Thread.currentThread().getName() + " m1 start...");
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + " m1 end");
	}
           
  • 靜态方法的代碼塊

這個類T在被類加載器加載到jvm記憶體中的時候,生成了一個特殊的類Class<T>。靜态方法的代碼塊鎖其實就是synchronized(T.class)

public synchronized static void m() { //這裡等同于synchronized(T.class)
		count--;
		System.out.println(Thread.currentThread().getName() + " count = " + count);
	}
           

引申問題:T.class 加載到記憶體中一定是單例麼?

并不一定是。如果使用的同一個ClassLoader那一定是,不同的ClassLoader不一定。

  • 對象鎖

任何對象都需要先拿到O這個對象的鎖

public void m() {
		synchronized(o) { //任何線程要執行下面的代碼,必須先拿到o的鎖
			count--;
			System.out.println(Thread.currentThread().getName() + " count = " + count);
		}
	}
           
  • 可重入鎖

同一個線程中,允許對同一個對象鎖多次。---必須是可重入鎖

synchronized void m1() {
		System.out.println("m1 start");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		m2();
		System.out.println("m1 end");
	}
	
	synchronized void m2() {
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("m2");
	}
           

synchronize的鎖更新

《沒錯,我就是廁所所長》

https://www.jianshu.com/p/b43b7bf5e052

https://www.jianshu.com/p/16c8b3707436

偏向鎖

當一個線程來了之後,隻是在MarkWord上面标記了狀态(線程的id值),其實并沒有真正的加鎖。下次還是這個線程通路的時候,發現線程id是一樣的,那麼就直接使用,不需要加鎖。

自旋鎖

在一個線程持有偏向鎖的時候,另一個線程也要來申請使用這個鎖,那麼就鎖更新進入了自旋鎖。

自旋鎖類似于一直while(true)循環,一直在檢視鎖狀态,是在核心态進行的。###自旋鎖速度快。

對應的線程不停的在CPU上運作,假設1W個線程争搶一把鎖,有一個1個獲得了鎖,剩下的9999個都在那裡自旋,是以CPU壓力是非常大的。 ###自旋鎖會占用CPU

是以自旋鎖适合-->線程數少,并且不會長時間運作的線程

重量級鎖(自旋10次之後,更新為重量級鎖)

重量級鎖是進入os,進入等待隊列,這個時候線程不再占CPU,進入了等待隊列。由CPU決定是什麼時候運作。

是以重量級鎖适合-->線程數量多,并且會長時間運作的線程

鎖:隻能更新,不能降級