Java啟動新執行緒的幾種方式(Runnable、Callable、CompletableFuture)
阿新 • • 發佈:2020-07-06
一、實現Runnable介面
public class RunnableDemo implements Runnable { public void run() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("in runnable demo"); } }
非阻塞呼叫
public static voidmain(String[] args) throws Exception { Thread runnableThread = new Thread(new RunnableDemo()); runnableThread.start(); System.out.println("in main"); }
輸出結果
in main
in runnable demo
可以看到執行緒的執行沒有阻塞當前執行緒
阻塞呼叫
public static void main(String[] args) throws Exception { Thread runnableThread= new Thread(new RunnableDemo()); runnableThread.start(); runnableThread.join(); System.out.println("in main"); }
輸出結果
in runnable demo
in main
Join會阻塞當前執行緒,一直等待自定義執行緒才返回。
二、實現Callable介面
在Runnable的例子中,Runnable介面有一個很大的缺陷就是run方法沒有返回值定義,主執行緒無法獲取到執行緒執行的結果。這個時候就需要Callable介面。
public class CallableDemo implements Callable<CallableDto> { public CallableDto call() throws Exception { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("in callable demo"); return new CallableDto(1); } } class CallableDto { private int id; public CallableDto(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
非阻塞呼叫
public static void main(String[] args) throws Exception { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10); Future<CallableDto> future = executor.submit(new CallableDemo()); System.out.println("in main"); }
輸出結果,如下所示,新啟動的執行緒沒有阻塞當前執行緒
in main
in callable demo
阻塞呼叫,且拿到結果
public static void main(String[] args) throws Exception { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10); Future<CallableDto> future = executor.submit(new CallableDemo()); CallableDto callableDto = future.get(); System.out.println("in main"); System.out.println("id from callable is " + callableDto.getId()); }
get方法首先會阻塞主執行緒,等待當前執行緒執行結束才返回,且返回執行緒的執行結果。
三、CompletableFuture方式
CompletableFuture是jdk1.8引入的api,做了進一步的封裝,使用者執行緒無需實現Callable介面也能啟動,且能夠返回使用者執行緒的執行結果
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
一個沒有實現Callable的普通方法
public class CompletableFutureDemo { public CompletableFutureDemoDto action() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("in CompletableFutureDemo "); return new CompletableFutureDemoDto(1); } } class CompletableFutureDemoDto { private int id; public CompletableFutureDemoDto(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
非阻塞呼叫
public static void main(String[] args) throws Exception { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10); CompletableFuture<CompletableFutureDemoDto> future = CompletableFuture.supplyAsync(() -> { return new CompletableFutureDemo().action(); }, executor); System.out.println("in main"); }
執行結果,可以看到,主執行緒沒有被阻塞
in main
in CompletableFutureDemo
阻塞呼叫且獲取結果
public static void main(String[] args) throws Exception { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10); CompletableFuture<CompletableFutureDemoDto> future = CompletableFuture.supplyAsync(() -> { return new CompletableFutureDemo().action(); }, executor); CompletableFutureDemoDto demoDto=future.join(); System.out.println("in main"); System.out.println("id from demoDto is " + demoDto.getId()); }
執行結果,主執行緒一直被阻塞,一直等到使用者執行緒返回
in CompletableFutureDemo
in main
id from demoDto is 1