鎖提供了兩種主要特性:互斥(mutual exclusion) 和可見性(visibility).可見性就是釋放鎖之前的共享數(shù)據(jù)更改對隨后獲得鎖的線程是可見的。
1 Synchronized
使用:synchronized可加在方法上,也可加在特定代碼塊上,括號中表示需要鎖的獨(dú)享
性能:托管給JVM執(zhí)行,Java1.6后性能提升到與Lock差不多,官方更提倡使用。
場景:普通場景推薦使用。
2 Lock
使用:通常使用ReentrantLock重入鎖,顯示指定起始位置和終止位置。加鎖和解鎖處使用lock()和unlock()方法,一般在finally塊中寫unlock()防止死鎖。
性能:用JAVA寫的控制鎖代碼
場景:復(fù)雜同步應(yīng)用推薦自定義使用。比如中斷線程控制權(quán),自定義wait-nitify線程,公平鎖等。
實(shí)現(xiàn):Lock接口的實(shí)現(xiàn)基本都是通過聚合了一個(gè)隊(duì)列同步器的子類來完成線程訪問控制的。
區(qū)別:ReentantLock表現(xiàn)為API層面的互斥鎖,synchronized表現(xiàn)為原生語法層面的互斥鎖。
優(yōu)點(diǎn):Lock提供了synchronized關(guān)鍵字不具備的主要特性:
1.嘗試非阻塞地獲取鎖;
2.能被中斷地獲取鎖;
3.超時(shí)獲取鎖。
獨(dú)占鎖:同一時(shí)間只有一個(gè)線程獲取鎖。再有線程嘗試加鎖,將失敗。 例如reentrantLock
共享鎖:同一時(shí)間可以有多個(gè)線程獲取鎖。例如FutureTask
3 擴(kuò)展:volatile
3.1 解釋
volatile用在多線程,同步變量。線程為了提高效率,將某成員變量(如A)拷貝了一份(如B),線程中對A的訪問其實(shí)訪問的是B。只在某些動(dòng)作時(shí)才進(jìn)行A和B的同步。因此存在A和B不一致的情況。volatile就是用來避免這種情況的。volatile告訴jvm,它所修飾的變量不保留拷貝,直接訪問主內(nèi)存中的(也就是上面說的A)
volatile會告知程序任何對該變量的訪問均需要從共享內(nèi)存中獲取,而對它的改變必須同步刷新回共享內(nèi)存,它能保證所有線程對變量訪問的可見性。
3.2 volatile與sychronized區(qū)別
volatile是程度較輕的synchronized,具備可見性,不具備操作原子性。volatile只是在線程內(nèi)存和“主”內(nèi)存間同步某個(gè)變量的值,而synchronized通過鎖定和解鎖某個(gè)監(jiān)視器同步所有變量的值,確保多個(gè)線程在同一時(shí)刻,只能由一個(gè)線程處于方法或同步塊中,這保證了線程對變量訪問的可見性和排他性。
volatile比synchronized的使用和執(zhí)行成本更低,不會引起線程上下文的切換和調(diào)度。Volatile一般情況下不能代替sychronized,因?yàn)?code>volatile不能保證操作的原子性,即使只是i++,實(shí)際上也是由多個(gè)原子操作組成:read i; inc; write i,假如多個(gè)線程同時(shí)執(zhí)行i++,volatile只能保證他們操作的i是同一塊內(nèi)存,但依然可能出現(xiàn)寫入臟數(shù)據(jù)的情況。