java 多執行緒-4
阿新 • • 發佈:2020-09-19
十四、sleep方法和wait方法的區別
【面試題】
- 相同點:
- 一旦執行方法,都可以使得當前執行緒進入阻塞狀態。
- 不同點:
- 兩個方法的宣告位置不同:Thread類宣告sleep();Object類中宣告wait()
- 呼叫的要求不同:sleep()可以在任何需要的場景下呼叫;wait()必須使用在同步程式碼塊或者同步方法中
- 關於是否收釋放同步監視器:如果有兩個方法都使用在同步程式碼塊或同步方法中,sleep()不會釋放同步監視器,而wait方法會釋放鎖
十五、JDK5.0新增執行緒建立方式
因此,java中有四種建立多執行緒的方式:
- 繼承Thread類,重寫run方法
- 實現Runnlable介面,重寫run方法
- 實現Callable介面,重寫cal方法
- 使用執行緒池【真實開發中,多數情況下使用的是執行緒池的方式】
15.1 新增方式一:實現Callable介面
15.1.1 Callable介面簡介
- 與使用Runnable相比, Callable功能更強大些 :
- 相比run()方法,可以有返回值
- 方法可以丟擲異常
- 支援泛型的返回值
- 需要藉助FutureTask類,比如獲取返回結果
15.1.2 藉助Future介面
Future介面
- 可以對具體Runnable、Callable任務的執行結果進行取消、查詢是 否完成、獲取結果等。
- FutrueTask是Futrue介面的唯一的實現類
- FutureTask 同時實現了Runnable, Future介面。它既可以作為 Runnable被執行緒執行 ,又可以作為Future得到Callable的返回值
15.1.3 列子
/** * 建立執行緒的方式三:實現Callable介面 */ public class RunCallable { public static void main(String[] args) { // 第三步:建立callable介面的實現類的物件 ThreadCallable threadCallable = new ThreadCallable(); // 第四步:將threadCallable物件傳入到FutureTask構造器中,建立futureTask物件 // 【FutureTask 同時實現了Runnable, Future介面。它既可以作為Runnable被執行緒執行,又可以作為Future得到Callable的返回值】 FutureTask futureTask = new FutureTask(threadCallable); // 第五步:將futureTask作為引數,傳遞到Thread類構造器中,建立Thread物件,並呼叫start方法 Thread thread = new Thread(futureTask); // 第六步:開啟執行緒 thread.start(); try { // 第七步:獲取callable中cal方法的返回值 // get方法獲取返回值 Object o = futureTask.get(); System.out.println("總和為:"+o); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } // 第一步:實現Callable介面 class ThreadCallable implements Callable{ private int sum; // 第二步:重寫run方法 @Override public Object call() throws Exception { for (int i = 0; i <= 100; i++) { if (i % 2 == 0) { System.out.println(i); } sum += i; } /*返回值是Object型別的,但是為什麼return sum沒有報錯? * 因為這裡做了一個自動裝箱操作,即把int型的sum,轉為Integer,而Integer繼承Object類,因此沒有報錯 * */ return sum; } }
15.2 新增方式二:使用執行緒池
15.2.1 執行緒池簡介
-
背景:
經常建立和銷燬、使用量特別大的資源,比如併發情況下的執行緒, 對效能影響很大。
-
思路:
提前建立好多個執行緒,放入執行緒池中,使用時直接獲取,使用完放回池中。可以避免頻繁建立銷燬、實現重複利用。類似生活中的公共交通工具。
-
好處:
- 提高響應速度(減少了建立新執行緒的時間)
- 降低資源消耗(重複利用執行緒池中執行緒,不需要每次都建立)
- 便於執行緒管理
- corePoolSize:核心池的大小
- maximumPoolSize:最大執行緒數
- keepAliveTime:執行緒沒有任務時最多保持多長時間後會終止
15.2.2 執行緒池API
執行緒池相關API
-
JDK 5.0起提供了執行緒池相關API:ExecutorService 和 Executors
-
ExecutorService:真正的執行緒池介面。常見子類ThreadPoolExecutor
- void execute(Runnable command) :執行任務/命令,沒有返回值,一般用來執行 Runnable
Future submit(Callable task):執行任務,有返回值,一般用來執行 Callable - void shutdown() :關閉連線池
-
Executors:工具類、執行緒池的工廠類,用於建立並返回不同型別的執行緒池
- Executors.newCachedThreadPool():建立一個可根據需要建立新執行緒的執行緒池
- Executors.newFixedThreadPool(n); 建立一個可重用固定執行緒數的執行緒池
- Executors.newSingleThreadExecutor() :建立一個只有一個執行緒的執行緒池
- Executors.newScheduledThreadPool(n):建立一個執行緒池,它可安排在給定延遲後運 行命令或者定期地執行。
15.2.3 列子
public class ThreadPool {
public static void main(String[] args) {
// 第一步:提供指定執行緒數量的執行緒池
ExecutorService executorService = Executors.newFixedThreadPool(10);
// executorService.submit();// 適合使用於callable
// 第二步:執行指定的執行緒的操作,需要提供實現Runnable介面或Callable介面實現類的物件
TestRunnable testRunnable = new TestRunnable();
TestRunnable2 testRunnable2 = new TestRunnable2();
executorService.execute(testRunnable);// 適合使用於runnable
executorService.execute(testRunnable2);// 適合使用於runnable
// 第三步:關閉執行緒池子
executorService.shutdown();
}
}
class TestRunnable implements Runnable{
private int i = 0;
@Override
public void run() {
while (true) {
if (i < 101) {
System.out.println(Thread.currentThread().getName()+"=======:"+i);
i++;
}else {
break;
}
}
}
}
class TestRunnable2 implements Runnable{
private int i = 0;
@Override
public void run() {
while (true) {
if (i < 101) {
System.out.println(Thread.currentThread().getName()+"&&&&&&&&"+i);
i++;
}else {
break;
}
}
}
}