1. 程式人生 > >Java多執行緒筆記總結

Java多執行緒筆記總結

1.執行緒的三種建立方式

對比三種方式:

  1. 通過繼承Thread類實現
  2. 通過實現Runnable介面
  3. 實現Callable介面

第1種方式無法繼承其他類,第2,3種可以繼承其他類;

第2,3種方式多執行緒可以共享同一個target物件,多個執行緒處理同一個資源;

一般使用第2,3種方式建立執行緒。

2.執行緒的生命週期

1.新建(new) 2.就緒(start) 3.執行(獲得cpu資源) 4.阻塞(sleep,IO阻塞等)4.死亡(執行完成,Exception/Error)
這裡寫圖片描述

3.執行緒常用方法

  1. join() :Thread物件呼叫,執行緒A呼叫join(),其他執行緒被阻塞,直到執行緒A執行完為止。

  2. setDaemon(true) : Thread物件呼叫,設定成後臺執行緒; 當所有前臺執行緒都死亡,後臺執行緒自動死亡。

  3. sleep(): 靜態方法,讓正在執行的執行緒暫停,進入阻塞狀態。
  4. yield(): 靜態方法,讓正在進行的執行緒暫停,進入就緒狀態,系統的執行緒排程器重新排程一次;只有優先順序比當前呼叫yield()的執行緒高或相同,並且處於就緒狀態的執行緒才能獲得執行。
  5. setPriority(int newPriority), getPriority(): 設定和獲取執行緒的優先順序;newPriority範圍1-10;Thread三個靜態常量,MAX_PRIORITY, 10; NORM_PRIORITY, 5; MIN_PRIORITY, 1;子執行緒和父執行緒具有相同的優先順序,優先順序高的執行緒比優先順序低的執行緒執行機會更多。

4.執行緒同步

多個執行緒訪問同一個資料時(執行緒排程的不確定性),很容易出現執行緒安全問題。解決辦法:引入同步監視器,任意時刻只能有一個執行緒獲得對同步監視器的鎖定,當同步程式碼塊執行結束後,該執行緒釋放對該同步監視器的鎖定。

“加鎖”—>”修改共享資源”->”釋放鎖”

同步程式碼塊

// obj就是同步監視器
synchronized(obj){
  同步程式碼塊
}

同步方法

使用synchronized修飾某個方法,則該方法稱為同步方法,同步方法的同步監視器是this;

只需對會改變競爭資源的方法進行同步。

任何執行緒在進入同步程式碼塊或同步方法前,必須獲得同步監視器的鎖定。
釋放同步監視器的鎖定的時機:

  1. 當前執行緒的同步程式碼塊,同步方法執行結束
  2. 當前執行緒在同步程式碼塊,同步方法中遇到break,return終止了執行
  3. 當前執行緒在同步程式碼塊,同步方法中出現了未處理的Error或Exception
  4. 執行了同步監視器物件的wait()方法

同步鎖(Lock)

Lock對共享資源的獨佔訪問,每次只能一個執行緒對Lock物件加鎖。
Lock,ReadWriteLock介面,對應的實現類ReentrantLock(可重入鎖),ReentrantReadWriteLock。

class A{
    private final ReentrantLock lock = ReentrantLock();

    public void method(){
        // 加鎖
        lock.lock();
        try{
            // 修改共享資源
        }finally{
            // 釋放鎖
            lock.unlock();
        }
    }
}

死鎖

兩個執行緒互相等待對方釋放同步監視器,就發生了死鎖。

執行緒池

在系統啟動時,建立大量空閒的執行緒,將一個Runnable物件或Callable物件傳給執行緒池,執行緒池會啟動一個執行緒執行對應的run()或call(),當run()或call()執行完成後,該執行緒返回到執行緒池成為空閒狀態,等待下個Runnable物件或Callable物件。

建立執行緒池

Executors工廠類,提供如下靜態方法建立不同的執行緒池:

// 具有快取功能的執行緒池,系統根據需要建立執行緒,這些執行緒會被快取線上程池中
newCachedThreadPool()
// 固定數量,可重用的執行緒池
newFixedThreadPool(int nThreads)
// 單執行緒的執行緒池
newSingleThreadExecutor()

// 指定執行緒數量,並可指定延遲時間才執行執行緒任務
newScheduleThreadPool(int corePoolSize)
// 單執行緒,並可指定延遲時間才執行執行緒任務
newSingleThreadScheduleExecutor()

前三個靜態方法return ExecutorService
後兩個靜態方法return ScheduledExecutorService

ExecutorService代表執行緒池,提供3個方法:

// 將一個Runnable物件提交給執行緒池,Future返回null
Future<?> submit(Runnable task)
// 將一個Runnable物件提交給執行緒池,Future返回指定結果result
Future<T> submit(Runnable task, T result)
// 將一個Callable物件提交給執行緒池,Future返回Callable物件中call()方法
Future<T> submit(Callable<T> task)

步驟:

  1. Executors靜態工廠類建立ExecutorService
  2. 建立Runnable或Callable物件,作為執行緒執行體
  3. 呼叫ExecutorService例項的submit()方法提交Runnable或Callable
  4. 執行緒池關閉,呼叫ExecutorService例項的shutdown()方法

ThreadLocal

執行緒區域性變數,把資料放在ThreadLocal中,就可以為每個執行緒建立一個該變數的副本,避免併發訪問的執行緒安全問題;


private ThreadLocal<T> threadLocal = new ThreadLocal<>();

// 當前執行緒副本中的值
T get();
// 刪除
void remove();
// 設定當前執行緒副本中的值
void set(T value);

與同步機制的區別:

同步機制是為了同步多個執行緒對共享資源的併發訪問,是多執行緒間通訊的有限方式;
ThreadLocal隔離多個執行緒的資料共享,避免多個執行緒間對共享資源的競爭,不需要對多個執行緒進行同步。

執行緒安全集合

通過Collections包裝成執行緒安全集合:

ArrayList, LinkedList, HashSet, TreeSet, HashMap, TreeMap等都是執行緒不安全;如果多個執行緒對這些集合讀,寫時,會破壞這些集合資料的完整性。

Collections提供靜態方法將這些集合包裝成執行緒安全的集合。

synchronizedCollection(Collection<T> c)

synchronizedList<List<T> list>

synchronizedMap(Map<K, V> map)

synchronizedSet(Set<T> set)
HashMap m = Collections.synchronizedMap(new HashMap);

執行緒安全集合:

ConcurrentHashMap, ConcurrentSkipListMap, ConcurrentSkipListSet, ConcurrentLinkedQueue, ConcurrentLinkedDeque

CopyOnWriteArrayList
CopyOnWriteArraySet