什麼是線程?講個故事給你聽,讓你沒法去背這個題,地址:https://blog.csdn.net/java_wxid/article/details/94131223
有幾種實現方式?
- 繼承Thread類
- 實現Runnable接口
- 實現Callable接口
- 線程池方式
優缺點
1.繼承Thread類
- 優點 、代碼簡單 。
- 缺點 、該類無法集成別的類。
2.實現Runnable接口
- 優點 、繼承其他類。 同一實現該接口的實例可以共享資源。
- 缺點 、代碼複雜
3.實現Callable
- 優點 、可以獲得異步任務的返回值
4.線程池 、實現自動化裝配,易於管理,循環利用資源。
代碼實現案例:
繼承Thread類,並重寫裏面的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();
實現Runnable接口,並實現裏面的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();
實現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(){//任務});
es.submit(new Runnable(){//任務});
...
es.shutdown();
問題擴展
在Java中Lock接口比synchronized塊的優勢是什麼?你需要實現一個高效的緩存,它允許多個用戶讀,但只允許一個用戶寫,以此來保持它的完整性,你會怎樣去實現它?
整體上來說Lock是synchronized的擴展版,Lock提供了無條件的、可輪詢的(tryLock方法)、定時的(tryLock帶參方法)、可中斷的(lockInterruptibly)、可多條件隊列的(newCondition方法)鎖操作。另外Lock的實現類基本都支持非公平鎖(默認)和公平鎖,synchronized只支持非公平鎖,當然,在大部分情況下,非公平鎖是高效的選擇。
線程池的實現原理:https://blog.csdn.net/java_wxid/article/details/101844786
JUC併發包:
- 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倒計時器:https://blog.csdn.net/java_wxid/article/details/99168098
- CyclicBarrier循環柵欄:https://blog.csdn.net/java_wxid/article/details/99171155
- Semaphore信號燈:https://blog.csdn.net/java_wxid/article/details/99174538
ThreadLocal與Lock和Synchronize區別
ThreadLocal與Lock和Synchronize區別
ThreadLocal爲每一個線程都提供了變量的副本,使得每個線程在某一時間訪問到的並不是同一個對象,這樣就隔離了多個線程對數據的數據共享。ThreadLocal採用了“以空間換時間”的方式,爲每一個線程都提供了一份變量,因此可以同時訪問而互不影響。
synchronized是利用鎖的機制,使變量或代碼塊在某一時該只能被一個線程訪問。同步機制採用了“以時間換空間”的方式,僅提供一份變量,讓不同的線程排隊訪問。
如果一個代碼塊被synchronized關鍵字修飾,當一個線程獲取了對應的鎖,並執行該代碼塊時,其他線程便只能一直等待直至佔有鎖的線程釋放鎖。事實上,佔有鎖的線程釋放鎖一般會是以下三種情況之一:
佔有鎖的線程執行完了該代碼塊,然後釋放對鎖的佔有;
佔有鎖線程執行發生異常,此時JVM會讓線程自動釋放鎖;
佔有鎖線程進入 WAITING 狀態從而釋放鎖,例如在該線程中調用wait()方法等。
synchronized 是Java語言的內置特性,可以輕鬆實現對臨界資源的同步互斥訪問。那麼,爲什麼還會出現Lock呢?試考慮以下三種情況:
Case 1 :
在使用synchronized關鍵字的情形下,假如佔有鎖的線程由於要等待IO或者其他原因(比如調用sleep方法)被阻塞了,但是又沒有釋放鎖,那麼其他線程就只能一直等待,別無他法。這會極大影響程序執行效率。因此,就需要有一種機制可以不讓等待的線程一直無期限地等待下去(比如只等待一定的時間 (解決方案:tryLock(long time, TimeUnit unit)) 或者 能夠響應中斷 (解決方案:lockInterruptibly())),這種情況可以通過 Lock 解決。
Case 2 :
我們知道,當多個線程讀寫文件時,讀操作和寫操作會發生衝突現象,寫操作和寫操作也會發生衝突現象,但是讀操作和讀操作不會發生衝突現象。但是如果採用synchronized關鍵字實現同步的話,就會導致一個問題,即當多個線程都只是進行讀操作時,也只有一個線程在可以進行讀操作,其他線程只能等待鎖的釋放而無法進行讀操作。因此,需要一種機制來使得當多個線程都只是進行讀操作時,線程之間不會發生衝突。同樣地,Lock也可以解決這種情況 (解決方案:ReentrantReadWriteLock) 。
Case 3 :
我們可以通過Lock得知線程有沒有成功獲取到鎖 (解決方案:ReentrantLock) ,但這個是synchronized無法辦到的。
上面提到的三種情形,我們都可以通過Lock來解決,但 synchronized 關鍵字卻無能爲力。事實上,Lock 是 java.util.concurrent.locks包 下的接口,Lock 實現提供了比 synchronized 關鍵字 更廣泛的鎖操作,它能以更優雅的方式處理線程同步問題。也就是說,Lock提供了比synchronized更多的功能。但是要注意以下幾點:
1)synchronized是Java的關鍵字,因此是Java的內置特性,是基於JVM層面實現的。而Lock是一個Java接口,是基於JDK層面實現的,通過這個接口可以實現同步訪問;
2)採用synchronized方式不需要用戶去手動釋放鎖,當synchronized方法或者synchronized代碼塊執行完之後,系統會自動讓線程釋放對鎖的佔用;而 Lock則必須要用戶去手動釋放鎖,如果沒有主動釋放鎖,就有可能導致死鎖現象。
關於讀寫鎖:https://blog.csdn.net/java_wxid/article/details/99165717