線程的同步:
1.同步代碼塊:synchronized(obj){};
2.同步函數(shù):public synchronized void add(int num);同步函數(shù)用的鎖對象是當前類本身岳掐,也就是this盛龄。
3.使用Lock鎖藐吮。(Lock是一個接口)
同步函數(shù)的鎖是固定的this辞州,同步代碼塊的鎖可以是任意的對象。
靜態(tài)同步函數(shù):public static synchronized void add(int num);靜態(tài)同步函數(shù)的鎖對象不是this砸琅,因為靜態(tài)方法沒有this宋距,還沒有new出來對象。靜態(tài)同步函數(shù)用的鎖是字節(jié)碼文件對象症脂,即this.getClass();也可以用Object.class;
著重說一下Lock鎖
Lock接口:將同步的隱式鎖操作變成了顯式鎖操作谚赎。同時更為靈活,可以一個鎖上加上多組監(jiān)視器诱篷。
方法:lock():獲取鎖壶唤,如果沒獲取到會一直等待;
tryLock()方法是有返回值的棕所,它表示用來嘗試獲取鎖闸盔,如果獲取成功,則返回true琳省,如果獲取失斢场(即鎖已被其他線程獲榷阕),則返回false击费,也就說這個方法無論如何都會立即返回拢蛋。在拿不到鎖時不會一直在那等待。
tryLock(long time, TimeUnit unit)方法和tryLock()方法是類似的蔫巩,只不過加了一個等待時間谆棱。
unlock():釋放鎖,通常需要定義在finally代碼塊中圆仔,因為如果發(fā)生異常而沒有釋放鎖垃瞧,可能會導(dǎo)致死鎖。
所有已知實現(xiàn)類:
ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock坪郭,第一個是可重入鎖皆警,后面兩個主要是讀寫鎖,用于讀寫操作截粗。
ReentrantLock:可重入的互斥鎖,所謂互斥就是同時只允許一個線程持有鸵隧。
ReadWriteLock:是一個接口绸罗,內(nèi)置兩個Lock,一個是讀的Lock豆瘫,一個是寫的Lock珊蟀。ReadWriteLock提供的方法有:
* readLock(): 返回一個讀的lock
* writeLock(): 返回一個寫的lock, 此lock是互斥的。
* 多個線程可同時得到讀的Lock外驱,但只有一個線程能得到寫的Lock育灸,
* 而且寫的Lock被鎖定后,任何線程都不能得到Lock昵宇。
* ReadWriteLockTest很適合處理類似文件的讀寫操作磅崭。
* 讀的時候可以同時讀,但不能寫瓦哎;寫的時候既不能同時寫也不能讀砸喻。
Condition接口:封裝了Object中的wait,notify,notifyAll方法,變成了Condition監(jiān)視器對象蒋譬,可以和任意鎖進行組合割岛。
方法:await(),signal(),signalAll(),分別對應(yīng)Object中的wait,notify,notifyAll方法犯助。
獲取一個鎖對象的監(jiān)視器實例:
Condition con = lock.newCondition();
一個lock對象上面可以掛多組Conditon對象癣漆。
wait()方法會釋放鎖。
interrupt():可以將線程從凍結(jié)狀態(tài)強制恢復(fù)到運行狀態(tài)中來剂买,讓線程具備cpu的執(zhí)行資格惠爽。但是會拋出InterruptedException異常癌蓖。只有使用lock鎖的線程才能夠響應(yīng)中斷,使用syncronized的線程不能夠響應(yīng)中斷疆股。
守護線程:setDaemon(true)费坊,也可以叫做后臺線程,如果所有的前臺線程都結(jié)束了旬痹,那么后臺線程無論是否處于凍結(jié)狀態(tài)附井。該 方法必須在啟動線程前調(diào)用。
join():比如主線程中有個線程t,當調(diào)用t.join()两残,主線程會凍結(jié)永毅,并等待t執(zhí)行完再執(zhí)行。
幾個概念:
1.可重入鎖
如果鎖具備可重入性人弓,則稱作為可重入鎖沼死。像synchronized和ReentrantLock都是可重入鎖。比如當syncronzied代碼塊或同步函數(shù)中又調(diào)用了另外一個同步代碼塊或者同步函數(shù)且它們使用的是同一個鎖對象 崔赌,那么當獲取到第一個同步代碼塊或者函數(shù)的鎖之后意蛀,在執(zhí)行第二個同步代碼塊或者鎖的時候,不會再去重復(fù)申請同步鎖健芭。
2.可中斷鎖
就是可以相應(yīng)中斷的鎖县钥,通過Thread.interrupt()方法。synchronized就不是可中斷鎖慈迈,而Lock是可中斷鎖若贮。
3.公平鎖
公平鎖即盡量以請求鎖的順序來獲取鎖。比如同時有多個線程在等待一個鎖痒留,當這個鎖被釋放時谴麦,等待時間最久的線程(最先請求的線程)會獲得該所,這種就是公平鎖伸头。
非公平鎖即無法保證鎖的獲取是按照請求鎖的順序進行的匾效。這樣就可能導(dǎo)致某個或者一些線程永遠獲取不到鎖。
在Java中恤磷,synchronized就是非公平鎖弧轧,它無法保證等待的線程獲取鎖的順序。
而對于ReentrantLock和ReentrantReadWriteLock碗殷,它默認情況下是非公平鎖精绎,但是可以設(shè)置為公平鎖。在ReentrantLock中定義了2個靜態(tài)內(nèi)部類锌妻,一個是NotFairSync代乃,一個是FairSync,分別用來實現(xiàn)非公平鎖和公平鎖。例如:ReentrantLock lock = new ReentrantLock(true);
Lock和synchronized有以下幾點不同:
1)Lock是一個接口搁吓,而synchronized是Java中的關(guān)鍵字原茅,synchronized是內(nèi)置的語言實現(xiàn);
2)synchronized在發(fā)生異常時堕仔,會自動釋放線程占有的鎖擂橘,因此不會導(dǎo)致死鎖現(xiàn)象發(fā)生;而Lock在發(fā)生異常時摩骨,如果沒有主動通過unLock()去釋放鎖通贞,則很可能造成死鎖 ? ? ? ? ? ? ? 現(xiàn)象,因此使用Lock時需要在finally塊中釋放鎖恼五;
3)Lock可以讓等待鎖的線程響應(yīng)中斷昌罩,而synchronized卻不行,使用synchronized時灾馒,等待的線程會一直等待下去茎用,不能夠響應(yīng)中斷;
4)通過Lock可以知道有沒有成功獲取鎖睬罗,而synchronized卻無法辦到轨功。
5)Lock可以提高多個線程進行讀操作的效率。