多線程/線程池/鎖相關面試總結

多線程(線程池)
啓動線程調用start() 方法,run()方法是線程啓動後須要執行的方法。

1. 繼承thread類
2. 實現runnable 接口
3. 實現callable 接口(call()方法,有返回值經過future對象的get()方法能夠獲取返回值,get()方法會阻塞,直到任務結果返回)
Callable 和 Future接口的區別
1. Callable規定的方法是call(),而Runnable規定的方法是run()。 
2. Callable的任務執行後可返回值,而Runnable的任務是不能返回值的。  
3. call()方法可拋出異常,而run()方法是不能拋出異常的。 
4. 運行Callable任務可拿到一個Future對象, Future表示異步計算的結果。 
5. 它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。 
6. 經過Future對象可瞭解任務執行狀況,可取消任務的執行,還可獲取任務執行的結果。 
7. Callable是相似於Runnable的接口,實現Callable接口的類和實現Runnable的類都是可被其它線程執行的任務
線程池:

線程池類繼承圖(1).jpg

經常使用的是 ThreadPoolExecutor 類 自定義 corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit, BlockingQueue數據庫

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

線程池公式 :緩存

maximumPoolSize = 2 * corePoolSize = 4 * cpu線程數
Executors線程池工具類:
Executors.new SingleThreadPoolExecutor(); 最大線程數爲1
Executors.new FixedThreadPoolExecutor(5) :核心線程數 = 最大線程數
Executors.new CachedThreadPoolExecutor() :緩存線程池
Executors.new ScheduledThreadPoolExecutor(5) :延遲/週期性線程池

single和fixed阻塞隊列最大爲 Interger.MAX_VALUE [2的31次方];
cached 和scheduled 最大線程數爲 Interger.MAX_VALUE [2的31次方];多線程

===========================================================================dom

鎖 :

鎖分類:
  • 可重入鎖:Synchronized和ReentrantLook都是可重入鎖,鎖的可重入性標明瞭鎖是針對線程分配方式而不是針對方法。例如調用Synchronized方法A中能夠調用Synchronized方法B,而不須要從新申請鎖。
  • 讀寫鎖:按照數據庫事務隔離特性的類比讀寫鎖,在訪問統一個資源(一個文件)的時候,使用讀鎖來保證多線程能夠同步讀取資源。ReadWriteLock是一個讀寫鎖,經過readLock()獲取讀鎖,經過writeLock()獲取寫鎖。
  • 可中斷鎖:可中斷是指鎖是能夠被中斷的,Synchronized內置鎖是不可中斷鎖,ReentrantLock能夠經過lockInterruptibly方法中斷顯性鎖。例如線程B在等待等待線程A釋放鎖,可是線程B因爲等待時間過久,能夠主動中斷等待鎖。
  • 公平鎖:公平鎖是指儘可能以線程的等待時間前後順序獲取鎖,等待時間最久的線程優先獲取鎖。synchronized隱性鎖是非公平鎖,它沒法保證等待的線程獲取鎖的順序,ReentrantLook能夠本身控制是否公平鎖。
兩種鎖的底層實現:
  • Synchronized:底層使用指令碼方式來控制鎖的,映射成字節碼指令就是增長來兩個指令:monitorenter和monitorexit。當線程執行遇到monitorenter指令時會嘗試獲取內置鎖,若是獲取鎖則鎖計數器+1,若是沒有獲取鎖則阻塞;當遇到monitorexit指令時鎖計數器-1,若是計數器爲0則釋放鎖。
  • Lock:底層是CAS樂觀鎖,依賴AbstractQueuedSynchronizer類,把全部的請求線程構成一個CLH隊列。而對該隊列的操做均經過Lock-Free(CAS)操做。
Synchronized和Lock比較
  • Synchronized是關鍵字,內置語言實現,Lock是接口。
  • Synchronized在線程發生異常時會自動釋放鎖,所以不會發生異常死鎖。Lock異常時不會自動釋放鎖,因此須要在finally中實現釋放鎖。
  • Lock是能夠中斷鎖,Synchronized是非中斷鎖,必須等待線程執行完成釋放鎖。
  • Lock可使用讀鎖提升多線程讀效率。
sychronized :
Lock :使用Lock必須在try…catch…塊中進行,而且將釋放鎖的操做放在finally塊中進行
ReentrantLock: (用法lock.tryLock() )
// 獲取鎖  
    void lock()   

    // 若是當前線程未被中斷,則獲取鎖,能夠響應中斷  
    void lockInterruptibly()   

    // 返回綁定到此 Lock 實例的新 Condition 實例  
    Condition newCondition()   

    // 僅在調用時鎖爲空閒狀態才獲取該鎖,能夠響應中斷  
    boolean tryLock()   

    // 若是鎖在給定的等待時間內空閒,而且當前線程未被中斷,則獲取鎖  
    boolean tryLock(long time, TimeUnit unit)   

    // 釋放鎖  
    void unlock()

tryLock()方法是有返回值的,它表示用來嘗試獲取鎖,若是獲取成功,則返回true;若是獲取失敗(即鎖已被其餘線程獲取),則返回false,也就是說,這個方法不管如何都會當即返回(在拿不到鎖時不會一直在那等待)。
tryLock(long time, TimeUnit unit)方法和tryLock()方法是相似的,只不過區別在於這個方法在拿不到鎖時會等待必定的時間,在時間期限以內若是還拿不到鎖,就返回false,同時能夠響應中斷。若是一開始拿到鎖或者在等待期間內拿到了鎖,則返回true。異步

ReentrantReadWriteLock : 讀寫鎖 (用法 lock.readLock().lock())
要點 : 共享讀,獨佔寫
//返回用於讀取操做的鎖  
Lock readLock()   
//返回用於寫入操做的鎖  
Lock writeLock()

代碼示例 :工具

// 讀數據
    public void get() {
        // 加讀鎖
        lock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " be ready to read data!");
            Thread.sleep((long) (Math.random() * 1000));
            System.out.println(Thread.currentThread().getName() + " have read data :" + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 釋放讀鎖
            lock.readLock().unlock();
        }
    }

    // 寫數據
    public void put(Object data) {
        // 加寫鎖
        lock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " be ready to write data!");
            Thread.sleep((long) (Math.random() * 1000));
            this.data = data;
            System.out.println(Thread.currentThread().getName() + " have write data: " + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 釋放寫鎖
            lock.writeLock().unlock();
        }

    }
}
相關文章
相關標籤/搜索