多執行緒考點

QLQ發表於2019-04-03

1. 執行緒與程式的區別?

  1. 地址空間: 同一程式的執行緒共享本程式的地址空間,程式是獨立的地址空間。
  2. 資源擁有: 同一程式內的執行緒共享本程式的資源如記憶體、I/O、cpu等,但是程式之間的資源是獨立的。
  3. 健壯性: 一個程式崩潰後,在保護模式下不會對其他程式產生影響,但是一個執行緒崩潰整個程式都死掉。所以多程式要比多執行緒健壯。
  4. 效能: 程式切換時,消耗的資源大,效率高。所以涉及到頻繁的切換時,使用執行緒要好於程式。同樣如果要求同時進行並且又要共享某些變數的併發操作,只能用執行緒不能用程式
  5. 執行過程: 每個獨立的程式程有一個程式執行的入口、順序執行序列和程式入口。但是執行緒不能獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制。
  6. 基本區別: 執行緒是處理器排程的基本單位,但是程式不是。

2. Thread 與 Runnable

  1. 適合多個相同的程式程式碼的執行緒去處理同一個資源
  2. 可以避免java中的單繼承的限制
  3. 增加程式的健壯性,程式碼可以被多個執行緒共享,程式碼和資料獨立

3. 執行緒返回值

  1. 主執行緒等待
  2. Thread的join方法
  3. Callable介面:FutureTask Or 執行緒池獲取

Callable介面實現:


import java.util.concurrent.Callable;

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception{
        String value="test";
        System.out.println("Ready to work");
        Thread.currentThread().sleep(5000);
        System.out.println("task done");
        return  value;
    }

}
複製程式碼
  1. FutureTask:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class FutureTaskDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> task = new FutureTask<String>(new MyCallable());
        new Thread(task).start();
        if(!task.isDone()){
            System.out.println("task has not finished, please wait!");
        }
        System.out.println("task return: " + task.get());

    }
}
複製程式碼
  1. 執行緒池獲取
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        Future<String> future = newCachedThreadPool.submit(new MyCallable());
        if(!future.isDone()){
            System.out.println("task has not finished, please wait!");
        }
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            newCachedThreadPool.shutdown();
        }
    }
}
複製程式碼

4. Thread的狀態

  1. New
  2. Runnable
  3. Waiting
  4. Timed Waiting
  5. Blocked
  6. Terminated

5. sleep與wait?

  1. sleep不釋放鎖,wait釋放所物件
  2. sleep是Thread的方法,wait是Object方法

6. 鎖池與等待池?

  1. 鎖池: 假設執行緒A已經擁有某個物件的鎖,由於B,C要呼叫這個物件的synchronized方法,B,C物件就會進入鎖池。
  2. 等待池: A執行緒呼叫wait()後,A釋放該物件的鎖,A就會進入該物件的等待池。

7. notify與notifyall?

  1. notifyAll會讓所有等待池的執行緒全部進入鎖池去競爭鎖機會
  2. notify是隨機選取一個

8. yield是暗示cpu釋放

9. interrupt函式

  1. 被拋棄的函式:stop
  2. interrupt是通知執行緒需要被中斷,如果執行緒處於被阻塞狀態,那麼執行緒將丟擲InterruptedException異常
  3. 如果執行緒處於活動狀態,則將標誌位設為true。被中斷執行緒將繼續執行,不受影響。

10. 執行緒狀態之間的轉化

synchronized

物件鎖

  1. 同步程式碼塊中的 this
  2. 同步非靜態方法

類鎖

  1. 同步程式碼塊 類.class
  2. 同步靜態方法

重入

同一物件進入同一資源

自旋鎖和自適應自旋鎖

  1. 自旋鎖:通過讓執行緒執行忙迴圈等待鎖釋放,不讓出cpu(鎖被佔用時長較長則更耗費效能,所以會有自旋次數限制)
  2. 自適應自旋鎖:自選次數不好設定,自適應自旋鎖會根據上次自旋時間決定是否自旋

鎖消除:

對上下文進行檢測,去除不可能存在競爭的鎖

鎖粗化

通過加鎖的範圍,減少反覆加鎖與減鎖

sychronized四種狀態

鎖膨脹的方向;無鎖-->偏向鎖-->輕量級鎖-->重量級鎖

  1. 偏向鎖:如果一個執行緒獲得了鎖,那麼鎖進入偏向模式,可省去鎖申請的操作
  2. 輕量級鎖:執行緒交替執行
  3. 重量級鎖:

鎖的記憶體語義

  1. 鎖釋放:java記憶體模型會把該執行緒對應的本地變數重新整理到主記憶體
  2. 鎖獲取:會將該執行緒對應的本地記憶體置為無效,臨界區必須從主記憶體讀取共享變數

sycronized 與 ReentryLock的區別

  1. 公平鎖:獲取鎖的順序按照先後呼叫lock方法順序
  2. 非公平鎖:搶佔順序不一定

happens-before

  1. 程式次序
  2. 鎖定
  3. volatile
  4. 傳遞
  5. 執行緒啟動
  6. 執行緒中斷
  7. 執行緒終結
  8. 物件終結

悲觀鎖 與 樂觀鎖

  1. 悲觀鎖始終假設衝突
  2. 樂觀鎖只在提交資料時檢測(CAS,J.U.C)

相關文章