理論:第八章:線程是什么,有幾種實(shí)現(xiàn)方式,它們之間的區(qū)別是什么,線程池實(shí)現(xiàn)原理,JUC并發(fā)包,ThreadLocal與Lock和Synchronize區(qū)別
什么是線程?講個(gè)故事給你聽(tīng),讓你沒(méi)法去背這個(gè)題,地址:https://blog.csdn.net/java_wxid/article/details/94131223
有幾種實(shí)現(xiàn)方式?
繼承Thread類(lèi)
實(shí)現(xiàn)Runnable接口
實(shí)現(xiàn)Callable接口
線程池方式
優(yōu)缺點(diǎn)
1.繼承Thread類(lèi)
優(yōu)點(diǎn) 、代碼簡(jiǎn)單 。
缺點(diǎn) 、該類(lèi)無(wú)法集成別的類(lèi)。
2.實(shí)現(xiàn)Runnable接口
優(yōu)點(diǎn) 、繼承其他類(lèi)。 同一實(shí)現(xiàn)該接口的實(shí)例可以共享資源。
缺點(diǎn) 、代碼復(fù)雜
3.實(shí)現(xiàn)Callable
優(yōu)點(diǎn) 、可以獲得異步任務(wù)的返回值
4.線程池 、實(shí)現(xiàn)自動(dòng)化裝配,易于管理,循環(huán)利用資源。
代碼實(shí)現(xiàn)案例:
繼承Thread類(lèi),并重寫(xiě)里面的run方法
class A extends Thread{
public void run(){
for(int i=1;i<=100;i++){
System.out.println("-----------------"+i);
}
}
}
A a = new A();
a.start();
實(shí)現(xiàn)Runnable接口,并實(shí)現(xiàn)里面的run方法
class B implements Runnable{
public void run(){
for(int i=1;i<=100;i++){
System.out.println("-----------------"+i);
}
}
}
B b = new B();
Thread t = new Thread(b);
t.start();
實(shí)現(xiàn)Callable
class A implements Callable<String>{
public String call() throws Exception{
//...
}
}
FutureTask<String> ft = new FutureTask<>(new A());
new Thread(ft).start();
線程池
ExcutorService es = Executors.newFixedThreadPool(10);
es.submit(new Runnable(){//任務(wù)});
es.submit(new Runnable(){//任務(wù)});
...
es.shutdown();
問(wèn)題擴(kuò)展
在Java中Lock接口比synchronized塊的優(yōu)勢(shì)是什么?你需要實(shí)現(xiàn)一個(gè)高效的緩存,它允許多個(gè)用戶讀,但只允許一個(gè)用戶寫(xiě),以此來(lái)保持它的完整性,你會(huì)怎樣去實(shí)現(xiàn)它?
整體上來(lái)說(shuō)Lock是synchronized的擴(kuò)展版,Lock提供了無(wú)條件的、可輪詢的(tryLock方法)、定時(shí)的(tryLock帶參方法)、可中斷的(lockInterruptibly)、可多條件隊(duì)列的(newCondition方法)鎖操作。另外Lock的實(shí)現(xiàn)類(lèi)基本都支持非公平鎖(默認(rèn))和公平鎖,synchronized只支持非公平鎖,當(dāng)然,在大部分情況下,非公平鎖是高效的選擇。
線程池的實(shí)現(xiàn)原理:https://blog.csdn.net/java_wxid/article/details/101844786
JUC并發(fā)包:
volatile的三大特性:https://blog.csdn.net/java_wxid/article/details/97611028
CompareAndSwap底層原理:https://blog.csdn.net/java_wxid/article/details/97611037
AtomicReference原子引用:https://blog.csdn.net/java_wxid/article/details/97611046
CountDownLatch倒計(jì)時(shí)器:https://blog.csdn.net/java_wxid/article/details/99168098
CyclicBarrier循環(huán)柵欄:https://blog.csdn.net/java_wxid/article/details/99171155
Semaphore信號(hào)燈:https://blog.csdn.net/java_wxid/article/details/99174538
ThreadLocal與Lock和Synchronize區(qū)別
ThreadLocal與Lock和Synchronize區(qū)別
ThreadLocal為每一個(gè)線程都提供了變量的副本,使得每個(gè)線程在某一時(shí)間訪問(wèn)到的并不是同一個(gè)對(duì)象,這樣就隔離了多個(gè)線程對(duì)數(shù)據(jù)的數(shù)據(jù)共享。ThreadLocal采用了“以空間換時(shí)間”的方式,為每一個(gè)線程都提供了一份變量,因此可以同時(shí)訪問(wèn)而互不影響。
synchronized是利用鎖的機(jī)制,使變量或代碼塊在某一時(shí)該只能被一個(gè)線程訪問(wèn)。同步機(jī)制采用了“以時(shí)間換空間”的方式,僅提供一份變量,讓不同的線程排隊(duì)訪問(wèn)。
如果一個(gè)代碼塊被synchronized關(guān)鍵字修飾,當(dāng)一個(gè)線程獲取了對(duì)應(yīng)的鎖,并執(zhí)行該代碼塊時(shí),其他線程便只能一直等待直至占有鎖的線程釋放鎖。事實(shí)上,占有鎖的線程釋放鎖一般會(huì)是以下三種情況之一:
占有鎖的線程執(zhí)行完了該代碼塊,然后釋放對(duì)鎖的占有;
占有鎖線程執(zhí)行發(fā)生異常,此時(shí)JVM會(huì)讓線程自動(dòng)釋放鎖;
占有鎖線程進(jìn)入 WAITING 狀態(tài)從而釋放鎖,例如在該線程中調(diào)用wait()方法等。
synchronized 是Java語(yǔ)言的內(nèi)置特性,可以輕松實(shí)現(xiàn)對(duì)臨界資源的同步互斥訪問(wèn)。那么,為什么還會(huì)出現(xiàn)Lock呢?試考慮以下三種情況:
Case 1 :
在使用synchronized關(guān)鍵字的情形下,假如占有鎖的線程由于要等待IO或者其他原因(比如調(diào)用sleep方法)被阻塞了,但是又沒(méi)有釋放鎖,那么其他線程就只能一直等待,別無(wú)他法。這會(huì)極大影響程序執(zhí)行效率。因此,就需要有一種機(jī)制可以不讓等待的線程一直無(wú)期限地等待下去(比如只等待一定的時(shí)間 (解決方案:tryLock(long time, TimeUnit unit)) 或者 能夠響應(yīng)中斷 (解決方案:lockInterruptibly())),這種情況可以通過(guò) Lock 解決。
Case 2 :
我們知道,當(dāng)多個(gè)線程讀寫(xiě)文件時(shí),讀操作和寫(xiě)操作會(huì)發(fā)生沖突現(xiàn)象,寫(xiě)操作和寫(xiě)操作也會(huì)發(fā)生沖突現(xiàn)象,但是讀操作和讀操作不會(huì)發(fā)生沖突現(xiàn)象。但是如果采用synchronized關(guān)鍵字實(shí)現(xiàn)同步的話,就會(huì)導(dǎo)致一個(gè)問(wèn)題,即當(dāng)多個(gè)線程都只是進(jìn)行讀操作時(shí),也只有一個(gè)線程在可以進(jìn)行讀操作,其他線程只能等待鎖的釋放而無(wú)法進(jìn)行讀操作。因此,需要一種機(jī)制來(lái)使得當(dāng)多個(gè)線程都只是進(jìn)行讀操作時(shí),線程之間不會(huì)發(fā)生沖突。同樣地,Lock也可以解決這種情況 (解決方案:ReentrantReadWriteLock) 。
Case 3 :
我們可以通過(guò)Lock得知線程有沒(méi)有成功獲取到鎖 (解決方案:ReentrantLock) ,但這個(gè)是synchronized無(wú)法辦到的。
上面提到的三種情形,我們都可以通過(guò)Lock來(lái)解決,但 synchronized 關(guān)鍵字卻無(wú)能為力。事實(shí)上,Lock 是 java.util.concurrent.locks包 下的接口,Lock 實(shí)現(xiàn)提供了比 synchronized 關(guān)鍵字 更廣泛的鎖操作,它能以更優(yōu)雅的方式處理線程同步問(wèn)題。也就是說(shuō),Lock提供了比synchronized更多的功能。但是要注意以下幾點(diǎn):
1)synchronized是Java的關(guān)鍵字,因此是Java的內(nèi)置特性,是基于JVM層面實(shí)現(xiàn)的。而Lock是一個(gè)Java接口,是基于JDK層面實(shí)現(xiàn)的,通過(guò)這個(gè)接口可以實(shí)現(xiàn)同步訪問(wèn);
2)采用synchronized方式不需要用戶去手動(dòng)釋放鎖,當(dāng)synchronized方法或者synchronized代碼塊執(zhí)行完之后,系統(tǒng)會(huì)自動(dòng)讓線程釋放對(duì)鎖的占用;而 Lock則必須要用戶去手動(dòng)釋放鎖,如果沒(méi)有主動(dòng)釋放鎖,就有可能導(dǎo)致死鎖現(xiàn)象。
關(guān)于讀寫(xiě)鎖:https://blog.csdn.net/java_wxid/article/details/99165717