Java多线程的主要两种方式
package main.com.imekaku; import org.junit.Test; /** * Created by liyuling(benzi) on 2017/6/13. * Class description : */ public class ThreadTest { @Test public void test1() { new Thread(new MyThread1()).start(); Thread thread = new MyThread2(); thread.start(); System.out.println("end"); try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } class MyThread1 implements Runnable { public void run() { long sum = 0; for (long i = 0; i < 1000000; i++) { sum += i; } System.out.println("implement: " + sum); } } class MyThread2 extends Thread { public void run() { long sum = 0; for (long i = 0; i < 1000000; i++) { sum += i; } System.out.println("extends: " + sum); } }
实现Runnable方式,匿名对象(匿名对象匿名类)创建
@Test public void test2() { new Thread(new Runnable() { public void run() { try { Thread.currentThread().sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("hi"); } }).start(); System.out.println("end"); try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("real end"); }
Callable和Future结合实现实现在执行完任务后获取返回值
@Test public void test3() { ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<String> future = executorService.submit(new Callable<String>() { public String call() throws Exception { Thread.currentThread().sleep(3 * 1000); return "hello world"; } }); try { System.out.println(future.get()); // 线程在这里阻塞 } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("end"); }
CompletableFuture 类使用
主动完成计算
CompletableFuture类实现了CompletionStage和Future接口,所以你还是可以像以前一样通过阻塞或者轮询的方式获得结果,尽管这种方式不推荐使用。参考地址:http://colobu.com/2016/02/29/Java-CompletableFuture/
@Test public void test4() { CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { try { Thread.currentThread().sleep(3 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Future Thread " + Thread.currentThread().getName()); return 0; }); System.out.println("Main Thread " + Thread.currentThread().getName()); try { System.out.println(future.get()); // 阻塞的方式 } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("end"); }
创建CompletableFuture对象
四个静态方法用来为一段异步执行的代码创建CompletableFuture对象
public static CompletableFuture<Void> runAsync(Runnable runnable) public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
runAsync
它以Runnable函数式接口类型为参数,所以CompletableFuture的计算结果为空。
supplyAsync
方法以Supplier函数式接口类型为参数,CompletableFuture的计算结果类型为U。
计算结果完成时的处理
当CompletableFuture的计算结果完成,或者抛出异常的时候,我们可以执行特定的Action。主要是下面的方法。
可以看到Action的类型是BiConsumer< ? super T,? super Throwable>,它可以处理正常的计算结果,或者异常情况。
方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其它的线程去执行(如果使用相同的线程池,也可能会被同一个线程选中执行)。
注意这几个方法都会返回CompletableFuture,当Action执行完毕后它的结果返回原始的CompletableFuture的计算结果或者返回异常。
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action) public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action) public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor) public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
@Test public void test5() { CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(ExecutorServiceTest::getNum); // 该语句执行时,就调用了getNum方法 Future<Integer> future = completableFuture.whenComplete((x, y) -> { // completableFuture 完成时,调用whenComplete方法 System.out.println("running.."); System.out.println("x = " + x); // x 表示ExecutorServiceTest::getNum 返回值 System.out.println("y = " + y); // y 表示该过程异常 }); System.out.println("Main Thread is running.. " + Thread.currentThread().getName()); try { System.out.println(future.get()); // 返回结果值 } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } private static Integer getNum() { System.out.println(Thread.currentThread().getName() + " is running.."); try { Thread.currentThread().sleep(3 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } return (int) (Math.random() * 100); }
// 执行结果 ForkJoinPool.commonPool-worker-1 is running.. Main Thread is running.. main running.. x = 70 y = null 70