Java執行緒(執行緒池、建立執行緒的第三種方法callable)
執行緒池
補充資料:Doug Lea (JCP組織的一人)對執行緒池部分貢獻巨大
常用執行緒池的介面和類:
Executor:執行緒池的頂級介面
ExecutorService:執行緒池介面可用submit(Runnable Task)提交任務程式碼。包含:Shutdown;
Shutdownnow等
Executors工廠類:可以通過這一個方法得到一個執行緒池
NewFixedThreadPool(int n Thread):獲取固定數量的執行緒池。引數:指執行緒池中執行緒的數量
NewCacheThreadPool()獲取動態數量的執行緒池,無上限
對於ExecutorService:需關注實現類TheadPoolExecutor,SheduledThreadPoolExecutor
Executors:1.建立固定執行緒個數的執行緒池
2.建立快取執行緒池,又任務多少來決定
3.建立單執行緒池
4.建立排程執行緒池 排程:週期、定時執行
在API中:
Shutdown:啟動一次順序關閉,執行以前提交的任務,但不接受新任務
ShutDownNow:試圖停止所有正在執行的活動任務,暫停處理正在等待的任務,並返回等待執行的任務列表
程式碼示例1 固定執行緒個數:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo {public static void main(String[] args) { // 1.建立固定執行緒個數的執行緒池 ExecutorService es=Executors.newFixedThreadPool(4); // 2.提交任務 Runnable run=new Runnable() { private int ticket; @Override public void run() { while (true) { if (ticket <= 0) { break; } System.out.println(Thread.currentThread().getName() + "賣完第:" + ticket + "張票"); ticket--; } } }; // 3.提交任務 for(int i=0;i<=4;i++) { es.submit(run); } // 4.關閉執行緒池 es.shutdown(); } }
程式碼示例 2 可變執行緒個數,由任務決定
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo { public static void main(String[] args) { // 1.建立固定執行緒個數的執行緒池 // ExecutorService es=Executors.newFixedThreadPool(4); ExecutorService es2=Executors.newCachedThreadPool(); // 2.提交任務 Runnable run=new Runnable() { private int ticket; @Override public void run() { while (true) { if (ticket <= 0) { break; } System.out.println(Thread.currentThread().getName() + "賣完第:" + ticket + "張票"); ticket--; } } }; // 3.提交任務 for(int i=0;i<=4;i++) { es2.submit(run); } // 4.關閉執行緒池 es2.shutdown(); } }
注:提交任務數不一定是4.要具體看執行結果
Excutors的另外兩種方法
3. ExecutorService e3=Executors.newSingleThreadExecutor();
4. ExecutorService e4=Executors.newScheduledThreadPool();
Callable介面
語法:
Public interface Callable<V>{public V call() throws Exception}
特點:有返回值;使用時需要先轉化為任務後被Thread呼叫
程式碼示例:
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; public class Demo02 { public static void main(String[] args) { // 功能需求:計算1-100的和並使用Callable介面 Callable<Integer> callable=new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+"開始計算"); int sum = 0; for (int j = 1;j<=100;j++){ sum+=j; Thread.sleep(100); } return sum; } }; // 把Callable轉化為可執行的任務 FutureTask<Integer> task = new FutureTask<>(callable); // 建立執行緒 Thread thread = new Thread(task); // 啟動執行緒 thread.start(); // 獲取結果 Integer sum= null; try { sum = task.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("結果是"+sum); } }
Callable與執行緒池的結合的使用
這種方法與執行緒池的配合更為緊密
優點:無需先轉化為task,再進行執行;
需求示例:使用Callable和執行緒池計算1-100的和
程式碼示例:
import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Demo03 { public static void main(String[] args) throws Exception { // 1. 建立執行緒池 ExecutorService es = Executors.newFixedThreadPool(1); // 2.提交任務Future:表示將要執行任務的結果 Future<Integer> future = es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+"開始計算"); int sum=0; for (int i=0;i<=100;i++){ sum+=i; } return sum; } }); // 3.獲取任務結果 System.out.println(future.get()); // 4.關閉執行緒池 es.shutdown(); } }
Future介面
功能:表示將要完成的任務的結果
案例需求:使用兩個執行緒,併發計算1-50和51-100的和,再進行彙總統計
Future.get()方法需要等待callable的方法執行完畢才可以繼續執行,即 同步
關於同步、非同步:我們現在手頭有兩個執行緒A\B,A在使用過程中會呼叫B執行緒。同步的含義是例如A需要執行三個部分,在第一個部分時呼叫了B,呼叫之後不繼續執行第二個部分而是等待B被呼叫完之後再繼續執行第二第三個部分。
非同步的含義是,A執行第一部分並呼叫了B執行緒,A不繼續等待B執行緒執行完而接著執行第二部分第三部分。
程式碼示例:
import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Demo4 { public static void main(String[] args) throws Exception{ // 1.建立執行緒池 ExecutorService es = Executors.newFixedThreadPool(2); // 2.建立任務及物件 Future<Integer> future =es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { int sum=0; for(int i=0;i<=50;i++){ sum+=i; } return sum; } }); Future<Integer> future2=es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { int sum=0; for(int i=51;i<=100;i++){ sum+=i; } return sum; } }); // 3.獲取結果 int sum=future.get()+future2.get(); System.out.println("結果是" + sum); // 4.關閉執行緒 es.shutdown(); } }