1. 執行緒與程式的區別?
- 地址空間: 同一程式的執行緒共享本程式的地址空間,程式是獨立的地址空間。
- 資源擁有: 同一程式內的執行緒共享本程式的資源如記憶體、I/O、cpu等,但是程式之間的資源是獨立的。
- 健壯性: 一個程式崩潰後,在保護模式下不會對其他程式產生影響,但是一個執行緒崩潰整個程式都死掉。所以多程式要比多執行緒健壯。
- 效能: 程式切換時,消耗的資源大,效率高。所以涉及到頻繁的切換時,使用執行緒要好於程式。同樣如果要求同時進行並且又要共享某些變數的併發操作,只能用執行緒不能用程式
- 執行過程: 每個獨立的程式程有一個程式執行的入口、順序執行序列和程式入口。但是執行緒不能獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制。
- 基本區別: 執行緒是處理器排程的基本單位,但是程式不是。
2. Thread 與 Runnable
- 適合多個相同的程式程式碼的執行緒去處理同一個資源
- 可以避免java中的單繼承的限制
- 增加程式的健壯性,程式碼可以被多個執行緒共享,程式碼和資料獨立
3. 執行緒返回值
- 主執行緒等待
- Thread的join方法
- 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;
}
}
複製程式碼
- 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());
}
}
複製程式碼
- 執行緒池獲取
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的狀態
- New
- Runnable
- Waiting
- Timed Waiting
- Blocked
- Terminated
5. sleep與wait?
- sleep不釋放鎖,wait釋放所物件
- sleep是Thread的方法,wait是Object方法
6. 鎖池與等待池?
- 鎖池: 假設執行緒A已經擁有某個物件的鎖,由於B,C要呼叫這個物件的synchronized方法,B,C物件就會進入鎖池。
- 等待池: A執行緒呼叫wait()後,A釋放該物件的鎖,A就會進入該物件的等待池。
7. notify與notifyall?
- notifyAll會讓所有等待池的執行緒全部進入鎖池去競爭鎖機會
- notify是隨機選取一個
8. yield是暗示cpu釋放
9. interrupt函式
- 被拋棄的函式:stop
- interrupt是通知執行緒需要被中斷,如果執行緒處於被阻塞狀態,那麼執行緒將丟擲InterruptedException異常
- 如果執行緒處於活動狀態,則將標誌位設為true。被中斷執行緒將繼續執行,不受影響。
10. 執行緒狀態之間的轉化
synchronized
物件鎖
- 同步程式碼塊中的 this
- 同步非靜態方法
類鎖
- 同步程式碼塊 類.class
- 同步靜態方法
重入
同一物件進入同一資源
自旋鎖和自適應自旋鎖
- 自旋鎖:通過讓執行緒執行忙迴圈等待鎖釋放,不讓出cpu(鎖被佔用時長較長則更耗費效能,所以會有自旋次數限制)
- 自適應自旋鎖:自選次數不好設定,自適應自旋鎖會根據上次自旋時間決定是否自旋
鎖消除:
對上下文進行檢測,去除不可能存在競爭的鎖
鎖粗化
通過加鎖的範圍,減少反覆加鎖與減鎖
sychronized四種狀態
鎖膨脹的方向;無鎖-->偏向鎖-->輕量級鎖-->重量級鎖
- 偏向鎖:如果一個執行緒獲得了鎖,那麼鎖進入偏向模式,可省去鎖申請的操作
- 輕量級鎖:執行緒交替執行
- 重量級鎖:
鎖的記憶體語義
- 鎖釋放:java記憶體模型會把該執行緒對應的本地變數重新整理到主記憶體
- 鎖獲取:會將該執行緒對應的本地記憶體置為無效,臨界區必須從主記憶體讀取共享變數
sycronized 與 ReentryLock的區別
- 公平鎖:獲取鎖的順序按照先後呼叫lock方法順序
- 非公平鎖:搶佔順序不一定
happens-before
- 程式次序
- 鎖定
- volatile
- 傳遞
- 執行緒啟動
- 執行緒中斷
- 執行緒終結
- 物件終結
悲觀鎖 與 樂觀鎖
- 悲觀鎖始終假設衝突
- 樂觀鎖只在提交資料時檢測(CAS,J.U.C)