線程是什麼,有幾種實現方式,它們之間的區別是什麼,線程池實現原理,JUC併發包,ThreadLocal與Lock和Synchronize區別

什麼是線程?講個故事給你聽,讓你沒法去背這個題,地址:https://blog.csdn.net/java_wxid/article/details/94131223

有幾種實現方式?

  1. 繼承Thread類
  2. 實現Runnable接口
  3. 實現Callable接口
  4. 線程池方式

優缺點

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併發包:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章