1.大纲
Runnable的不足
CallAble的接口
Future类
一:Runnable的不足
1.不足
不能返回返回值
run方法不能抛出异常,因为大部分可以处理异常的不是我们写的,所以,要想处理,还是要在run里进行自己处理异常
2.程序
@FunctionalInterface public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }
二:CallAble接口
1.说明
实现call
2.程序
@FunctionalInterface public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception; }
三:Future
1.作用
不要要等待,需要的时候,到future获取数据
2.Callable与Future的关系
可以使用Future.get来获取Callable接口返回的执行结果
可以通过Future.isDone来判断任务是否已经执行完成,
如果call()还没有执行完成,调用get的线程将会被阻塞,只有等运行完成,才能获取到结果,然后主线程才回切换到runnable的状态
3.总结
Future是一个存储器,存储了call这个任务的结果
4.主要方法
5.get方法
V get() throws InterruptedException, ExecutionException;
6.get(timeout,unit)
V get(long timeout, TimeUnit unit)
超时很常见
超时不获取,任务需要取消
7.cancel方法
boolean cancel(boolean mayInterruptIfRunning);
8.isDone
boolean isDone();
是否完毕,不一定是成功的,抛出异常也是执行完毕
9.isCancel
boolean isCancelled();
四:代码演示
1.基础的用法
线程池的submit方法返回Future对象
public class OneFuture { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); Future<Integer> future = executorService.submit(new CallableTask()); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } executorService.shutdown(); } static class CallableTask implements Callable<Integer>{ @Override public Integer call() throws Exception { Thread.sleep(3000); return new Random(10).nextInt(); } } }
效果:
Connected to the target VM, address: '127.0.0.1:49767', transport: 'socket' -1157793070 Disconnected from the target VM, address: '127.0.0.1:49767', transport: 'socket' Process finished with exit code 0
2.lambda方式
public class TwoFuture { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); Callable<Integer> callable = ()->{ Thread.sleep(3000); return new Random(10).nextInt(); }; Future<Integer> future = executorService.submit(callable); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } executorService.shutdown(); } }
3.多个任务,使用Future数组来获取结果
package com.jun.juc.feature; import java.util.ArrayList; import java.util.Random; import java.util.concurrent.*; public class ThreeFuture { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); Callable<Integer> callable = ()->{ Thread.sleep(3000); return new Random(10).nextInt(); }; ArrayList<Future> futures = new ArrayList<>(); for(int i=0;i<20;i++){ Future<Integer> future = executorService.submit(callable); futures.add(future); } // for(int i=0;i<20;i++){ Future<Integer> future = futures.get(i); try { Integer integer = future.get(); System.out.println(integer); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } }
结果:
可以发现,每次是两个结果返回。因为线程池中才两个线程。
4.任务执行过程中抛出异常
package com.jun.juc.feature; import java.util.Random; import java.util.concurrent.*; public class FourFuture { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); Callable<Integer> callable = ()->{ throw new IllegalArgumentException("callable异常"); }; Future<Integer> future = executorService.submit(callable); try { Thread.sleep(5000); future.get(); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("InterruptedException异常了"); } catch (ExecutionException e) { e.printStackTrace(); System.out.println("ExecutionException异常了"); } executorService.shutdown(); } }
只有在get的时候,才会抛出异常,而且异常是ExecutionException
5.获取任务超时
package com.jun.juc.feature; import java.util.concurrent.*; public class FiveFuture { private static final Ad DEFAULT_AD = new Ad("无网络时候的默认广告"); private static final ExecutorService exec = Executors.newFixedThreadPool(10); static class Ad { String name; public Ad(String name) { this.name = name; } @Override public String toString() { return "Ad{" + "name='" + name + '\'' + '}'; } } static class FetchAdTask implements Callable<Ad> { @Override public Ad call() throws Exception { try { Thread.sleep(3000); } catch (InterruptedException e) { System.out.println("sleep期间被中断了"); return new Ad("被中断时候的默认广告"); } return new Ad("旅游订票哪家强?找某程"); } } public void printAd() { Future<Ad> f = exec.submit(new FetchAdTask()); Ad ad; try { ad = f.get(2000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { ad = new Ad("被中断时候的默认广告"); } catch (ExecutionException e) { ad = new Ad("异常时候的默认广告"); } catch (TimeoutException e) { ad = new Ad("超时时候的默认广告"); System.out.println("超时,未获取到广告"); boolean cancel = f.cancel(true); System.out.println("cancel的结果:" + cancel); } exec.shutdown(); System.out.println(ad); } public static void main(String[] args) { FiveFuture timeout = new FiveFuture(); timeout.printAd(); } }
运行结果:
Disconnected from the target VM, address: '127.0.0.1:55224', transport: 'socket' 超时,未获取到广告 sleep期间被中断了 cancel的结果:true Ad{name='超时时候的默认广告'} Process finished with exit code 0
说明:
cancel方法传入true,则运行的方法会抛出异常
6.calcel的说明
7.传入false的作用
如果任务没有开始,false传入,任务会被打上标记,然后任务不会被执行。
8.传入true还是false
true适用:
任务能够处理interrupt
false:
未能处理interrupt的任务
不清楚任务是否支持取消
五:FutureTask创建Future
1.结构
2.程序
package com.jun.juc.feature; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; /** * 描述: 演示FutureTask的用法 */ public class FutureTaskDemo { public static void main(String[] args) { Task task = new Task(); FutureTask<Integer> integerFutureTask = new FutureTask<>(task); // new Thread(integerFutureTask).start(); ExecutorService service = Executors.newCachedThreadPool(); service.submit(integerFutureTask); try { System.out.println("task运行结果:"+integerFutureTask.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } class Task implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("子线程正在计算"); Thread.sleep(3000); int sum = 0; for (int i = 0; i < 100; i++) { sum += i; } return sum; } }
效果:
Connected to the target VM, address: '127.0.0.1:55709', transport: 'socket' 子线程正在计算 task运行结果:4950 Disconnected from the target VM, address: '127.0.0.1:55709', transport: 'socket' Process finished with exit code 1