Java启动新线程的几种方式(RunnableCallableCompletableFuture)
Posted Catch Spark. Code
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java启动新线程的几种方式(RunnableCallableCompletableFuture)相关的知识,希望对你有一定的参考价值。
一、实现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 void main(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
以上是关于Java启动新线程的几种方式(RunnableCallableCompletableFuture)的主要内容,如果未能解决你的问题,请参考以下文章