Future
Future接口提供了异步并行计算的功能,可以为主线程开一个分支任务,专门为主线程处理耗时和费力的复杂任务。
(FutureTask)实现类满足三个特点,1,多线程 2,有返回 3,异步任务
Future(FutureTask) 优缺点
优点:future+线程池异步多线程任务配合,能显著提高程序的运行效率
缺点: 调用get()方法求结果,一旦计算没有完成,会导致程序阻塞
如果采用轮询的机制,判断是否完成 while(futureTask.isDone()) , 完成后调用get()方法返回结果,缺点是比较耗费性能,
所以,future对于结果的获取不是很友好,只能通过阻塞或者轮询的方式去获取结果。
completableFuture
java8在Future的基础上新增了completableFuture,有如下新特性
1,可以传入回调对象,当任务完成或异常时,自动调用回调对象的回调方法(规避了future的缺点)
2,多个任务前后依赖组合处理
3,对计算速度选最快
创建completableFure有四个静态方法 (也可以通过new创建,但不推荐)
runAsync无返回值
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
supplyAsync无返回值
public static <U>CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U>CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{ System.out.println(Thread.currentThread().getName()); }, //此处可以指定线程池 ); System.out.println(completableFuture.get());
返回结果
ExecutorService threadPool = Executors.newFixedThreadPool(3); CompletableFuture<String> completableFuture2 = CompletableFuture.supplyAsync(()->{ System.out.println(Thread.currentThread().getName()); return "this is supplyAsync"; },threadPool); System.out.println(completableFuture2.get());
返回结果
通过.whenComplete和.exceptionally实现任务完成或抛出异常时执行的步骤
/*
注意:最好使用自己创建的线程池,如果用默认的ForkJoinPool的话,ForkJoinPool会随着主线程执行完一起销毁,
可能会导致completableFuture执行不玩完,没有返回结果
*/
ExecutorService threadPool = Executors.newFixedThreadPool(3); CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(()->{ System.out.println(Thread.currentThread().getName() + "come in"); int result = ThreadLocalRandom.current().nextInt(10); try {TimeUnit.MILLISECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();} System.out.println("1秒钟后出结果:" + result);
//模拟异常 int i = result / 0; return result; },threadPool).whenComplete((v,e)-> { if ( e == null){ System.out.println("----计算完成,更新系统value = " + v); } }).exceptionally(e -> { e.printStackTrace(); System.out.println("异常情况" + e.getCause() + "\t" + e.getMessage()); return null; }); System.out.println(Thread.currentThread().getName() + "主线程先去忙其他任务"); threadPool.shutdown(); }
返回结果(正常情况)
(异常情况)
CompletableFuture关于线程池选择
1没有传入自定义线程池,都用默认线程池ForkJoinPool;
2传入了一一个自定义线程池,
如果你执行第一一个任务的时候,传入了一个自定义线程池:
调用thenRun方法执行第:二个任务时,则第二个任务和第-一个任务是共用同一个线程池。
调用thenRunAsync执行第二个任务时
则第一个任务使用的是你自己传入的线程池,第二个任务使用的是ForkJoin线程池
3备注
有可能处理太快,系统优化切换原则,直接使用main线程处理
其它如: thenAccept和thenAcceptAsync, thenApply 和thenApplyAsync等,它们之间的区别也是同理
线程中断的三个方法
*线程中断的思想: 一个线程应该自己决定自己的命运,不该由其他线程来强行中断或停止,所以中断是一种协商机制
三种线程唤醒对比
方法1: synchronized, wait(), notify()
object objectLock = new object(); new Thread(() -> { synchronized (objectLock){ System. out . println( Thread. current Thread(). getName()+"\t ----come in"); try { objectLock .wait(); } catch (InterruptedException e) { e. printStackTrace(); System. out . println(Thread . current Thread(). getName()+"\t ---- 被唤醒"); } }, name: "t1"). start(); //暂停几秒钟线程 try { TimeUnit .SECONDS . sleep( timeout: 1); } catch (InterruptedException e) { e. printstackTrace(); } new Thread(() ->{ synchronized (objectLock){ objectlock.notify(); System. out . println( Thread. current Thread().getName()+"\t |"); } }, name: "t2").start();
方法2: Lock, condition.wait(), condition.signal()
new Thread(() -> { lock.1ock(); try { System. out . println( Thread. current Thread(). getName()+"\t ----come in"); condition. await(); System. out . println(Thread . current Thread(). getName()+"\t ---- 被唤醒"); } catch (InterruptedException e) { e. printStackTrace(); } finally { lock.unlock(); } }, name: "t1"). start(); //暂停几秒钟线程 try { TimeUnit . SECONDS . sleep( timeout: 1); } catch (InterruptedException e) { e. printStackTrace(); } new Thread(() -> { lock.1ock(); try condition. signal(); System. out . println( Thread. current Thread(). getName()+"\t ----发出通知"); S中。 }finally { lock . unlock(); }
方法3: LockSupport, static park(), static unpark()
public static void main(String[] args) Thread t1 = new Thread(() -> { try { TimeUnit .SECONDS.sleep( timeout:3); } catch (InterruptedException e) { e.printstackTrace(); } System. out . println(Thread. current Thread( ).getName() + "\t ----come in"+System. currentT imeMillis()); LockSupport . park(); System . out . println(Thread . current Thread() . getName() + "\t ---- 被唤醒" +System. currentTimeMillis()); },name: "t1"); t1.start(); //暂停几秒钟线程 //try { TimeUnit. SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { LockSupport . unpark(t1); System. out . println( Thread . current Thread() . getName()+"\t ----发出通知"); }, name: "t2").start(); }
对比:synchronized和lock的唤醒需要在锁块内进行,并且需要先等待,后唤醒。
LockSupport没有锁的要求,并且可以先给线程一个通行证,让线程在收到下一个等待指令时跳过等待。无论执行多少次unpark(),通行证只能储存一个,如果线程收到连续两个park()指令,第二条park指令仍然会让线程等待。
标签:Thread,getName,System,线程,println,CompletableFuture,out From: https://www.cnblogs.com/tyleaf/p/16981053.html