Java關鍵字synchronized學習筆記

一、synchronized定義java

Java語言的關鍵字,可用來給對象方法或者代碼塊加鎖,當它鎖定一個方法或者一個代碼塊的時候,同一時刻最多隻有一個線程執行這個段代碼。當兩個併發線程訪問同一個對象object中的這個加鎖同步代碼塊時,一個時間內只能有一個線程獲得執行。另外一個線程必須等待當前線程執行完這個代碼塊之後才能執行該代碼塊。然而,當一個線程訪問object的一個加鎖代碼塊時,另外一個線程仍然能夠訪問該object中的非加鎖代碼塊緩存

注意:synchronized沒法修飾單個對象,synchronized修飾的應該是對象+方法或者對象+代碼塊的組合。多線程

對象+方法:直接修飾方法便可;這種方式中沒有體現出對象,但其實該類的實例就是被鎖的對象了。併發

public synchronized void A(){
		s("A");
	}

對象+代碼塊:這種方式就比較明顯了,this就是指該類的實例,{}中的內容則是代碼塊。異步

public void A(){
		synchronized (this) {
			s("A");
		}
	}

上面兩個例子是等價的。ide

二、打個比方來理解this

synchronized其實就是一個遊戲spa

遊戲場景:一個大房子(對象),裏面有多個房間(方法),有些是鎖着的,有些是沒鎖的線程

遊戲人物:管理員(JVM),玩家(線程)code

遊戲規則:

(1)沒有上鎖的房間能夠隨時使用,也能夠多個玩家同時使用

(2)上了鎖的房間只限一個玩家使用,並且只有一把鑰匙能夠打開

(3)鑰匙能夠跟管理員拿,若同時有多個玩家想拿同個鑰匙,管理員會隨機給其中一個玩家

(4)玩家用完房間後必須把鑰匙歸還管理員(即便想再次使用,也得先還管理員,再跟管理員要;若是其餘玩家也要這個鑰匙,則會隨機給其中一個)

三、Android用到的地方

首先從定義就能夠知道,synchronized只有在多線程的場景下才有存在的意義。

那麼Android中用到多線程的地方,舉個常見的例子,就是GridView異步加載本地圖片

因爲加載圖片挺耗時的,因此在同個線程中把多張圖片一次加載完是很不明智的,何況本地圖片但是不少的。

因此這時咱們會考慮到使用線程池來加載圖片。

那麼線程多了天然也會面臨一個問題:可能出現多個線程同時在加載同一張圖片,會產生什麼問題?

事實上,這也是必然會出現的問題;好比你快速向上滑動圖片列表(在圖片很是多的狀況下),而後又迅速向下滑動,這時若是以前正在加載的圖片還沒加載完,就會有新的線程來再加載那張圖片;兩個線程加載同個圖片,這就是所謂的內存泄露;內存泄露還不至於報錯,可是內存泄露的地方多了,不免會報OOM,因此須要避免內存泄露。

這時,若是使用synchronized來鎖住加載圖片的代碼塊,就能夠避免了。

注意:鎖住加載圖片的代碼塊後GridView是一張一張加載圖片的。

提醒:鎖住不一樣對象的同個代碼塊沒有任何意義,相似下面這樣的代碼都是無心義的!

public class Test implements Runnable{
	
	@Override
	public void run() {
		synchronized (this) {
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName());
			}
		}
	}
	
	public static void main(String...arg){
		new Thread(new Test(),"A").start();
		new Thread(new Test(),"B").start();
	}

}

應該寫成這樣:

Test test = new Test();
		new Thread(test,"A").start();
		new Thread(test,"B").start();

四、題外話

上面的例子中用synchronized鎖住加載圖片的代碼後GridView是一張張加載圖片的,可是這樣作感受多線程就沒什麼意義了;確實,畢竟synchronized的定義已經說的很清楚了,就是爲了防止多個線程幹同件事的;若是你實在受不了一張張的加載圖片的話,那就只能放棄synchronized了。

其實,上面我說的GridView加載圖片的例子,並沒這麼簡單,我只是爲了更好理解才這樣描述;實際上在項目中是多線程+緩存+synchronized多線程+緩存就解決了內存泄露的問題了,而synchronized是爲了讓圖片一張張加載的效果。

相關文章
相關標籤/搜索