8535.com-新浦京娱乐场官网|欢迎您

Callable和Future、FutureTask的采纳,callablefuturetask

来源:http://www.dnamique.com 作者:计算机网络 人气:57 发布时间:2019-10-07
摘要:Callable和Future、FutureTask的使用,callablefuturetask   并发的就学与行使类别 第四篇 在Java中,开启三个线程的独一方法是,是因而Thread的start方法,并且在线程中实践的Runnable的run方法。无

Callable和Future、FutureTask的使用,callablefuturetask

 

并发的就学与行使类别 第四篇

在Java中,开启三个线程的独一方法是,是因而Thread的start方法,并且在线程中实践的Runnable的run方法。无论是线程池照旧接下去要介绍的Callable,Future依旧线程池,最中央最根本的依旧调用到Thread.start()–>Runnable.run(),其余的类的出现能够以为是更方便的运用Thread和Runnable,以此为核心会更易于精晓Java的产出框架。

即使如此Thread和Runnable类使得八线程编制程序轻松直接,但有三个重疾正是:在施行完职务之后无法赢得实施结果。假使须求取得实行结果,就务须透过共享变量可能利用线程通讯的措施来到达效果,那样使用起来就相比麻烦。因而从Jdk1.5上马,有了一多样的类的出现来消除这么些标题,如Callable和Future,FutureTask以及下篇要讲到的线程池从使用到原教育学习Java线程池。

新浦京娱乐场官网,而自从Java 1.5最初,就提供了Callable和Future以及FutureTask,通过它们得以在职分试行实现之后拿到职务推行结果。

福如东海原理

Thread和Runnable

先是看Thread和Runnable的达成多线程义务的法规。

以下是简化后的代码,为了便于明白。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Thread implements Runnable { Runnable target;   public Thread(Runnable runnable) {   target = Runnable;   //省略其他初始化线程的任务 }   public void start() { nativeCreate(this, stackSize, daemon);//native方法开启多线程,并调用run方法 }   public void run() { if (target != null) { target.run(); } } }

能够看来target是二个Runnble对象,通过二个卓绝的点缀情势来扩展Runnable,借使不扩散,默以为null,须求协调完毕run方法来在新线程里实施职分,不然线程不会做其余职业就停止。所以无论怎么变化,最终都以Thread的start方法开启新线程,run方法在那个新开启的线程里施行职分,当然run方法也能够独自调用,但所在线程是调用者的线程。

装饰者模式的典型特点:装饰后的类和被装饰的类,类型不变(继承Runnable),提供新的行为,方法(start()等),关于设计模式的详细细节,见常见的设计模式解读。

Callable和Future,FutureTask

先通过UML图来看它们和Thrad,Runnable之间的涉及:

新浦京娱乐场官网 1

Callable与Runnable的效果与利益大约相像,Callable中有三个call()函数,可是call()函数有再次回到值,而Runnable的run()函数不可能将结果再次来到给顾客程序。

Future不怕对Callable职责的实践结果开展裁撤、查询是不是形成、获取结果、设置结果操作。个中的get()方法正是用来获得Callable的call()结果的。

FutureTask是Future的具体贯彻类,完毕了get()等方法来对调整Callabel的表现,又因为Thread只可以实行Runnable,所以FutureTask完毕了Runnable接口。

因为FutureTask供给在Thread中实行,所以须要在run()方法中完结具体的落到实处:

1 2 3 4 5 6 7 8 9 10 //简化后的代码,为了方便理解 public void run() { Callable<V> c = callable;   if (c != null && state == NEW) { V result; result = c.call(); set(result); } }

透过get方法来收获结果,get()是个闭塞方法,直到结果回到,只怕暂停爆发。还是能够透过get(long timeout, TimeUnit unit)方法调整等待结果的最大时间。

1 2 3 4 5 6 public V get() throws InterruptedException, ExecutionException { int s = state; if (s <= COMPLETING) s = awaitDone(false, 0L);//阻塞等待 return report(s); }

能够看来FutureTask的run方法其实的天职是在Callable的call中做到,FutureTask的兑现格局选择了适配器格局来成功。

借使构造函数字传送入的是Runnable,则通过Executors的静态函数callable(Runnable task,…)将Runnable转变为Callable类型:

1 2 3 4 5 6 public static Callable callable(Runnable task, T result) {   if (task == null) throw new NullPointerException();   return new RunnableAdapter(task, result); }
适配器模式的典型特点:包装另一个对象(包装了Callable),提供不同的接口(Runnable接口)

Callable和Future,FutureTask不时轻巧令人记念混乱,精晓后就明白了实在Future和FutureTask正是用来将Callable包装成三个Runnable,那样技艺够在Thread中实行,同期提供将结果重回的功用,四个类总是同不时候出现,全部精晓为是二个方可拿走重返结果的Runnable。

使用

那么怎么利用这些类呢啊?由于FutureTask实现了Runnable,由此它不仅能够因此Thread包装来直接实行,也足以交给给ExecuteService来施行,在Thread中,就像使用Runnable同样。

有关线程池的更加多细节将要下一篇小说中张开疏解

示范代码如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 /** * Created by SilenceDut on 16/7/15. **/   public class FutureTest {   public static void main(String[] args) { FutureTest futureTest = new FutureTest(); futureTest.useExecutor(); futureTest.useThread(); }   private void useExecutor() {   SumTask sumTask = new SumTask(1000); ExecutorService executor = Executors.newCachedThreadPool();   FutureTask<Integer> futureTask = new FutureTask<Integer>(sumTask);   executor.submit(futureTask); executor.shutdown();   try { System.out.println(Thread.currentThread().getName()+"::useExecutor运行结果" + futureTask.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }   private void useThread() { SumTask sumTask = new SumTask(500);   FutureTask<Integer> futureTask = new FutureTask<Integer>(sumTask) { @Override protected void done() { super.done(); try { // 这是在后台线程 System.out.println(Thread.currentThread().getName()+"::useThread运行结果" + get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } };   Thread thread = new Thread(futureTask); thread.start();   try { //这是在主线程,会阻塞 System.out.println(Thread.currentThread().getName()+"::useThread运行结果" + futureTask.get().getName()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }   class SumTask implements Callable<Integer> { int number;   public SumTask(int num) { this.number = num; }   @Override public Integer call() throws Exception {   System.out.println(Thread.currentThread().getName()); Thread.sleep(5000);   int sum = 0; for (int i = 0; i < number; i++) { sum += i; } return sum; } } }

结果:

pool-1-thread-1
main::useExecutor运行结果499500
Thread-0
main::useThread运行结果124750
Thread-0::useThread运行结果124750

FutureTask.get()是阻塞的,useExecutor()和useThread()也会阻塞。这里只是表明FutureTask.get()所在的线程是调用者所在的线程,在Android中使用的话,日常是在FutureTask的done方法中get,那时get就是在后台线程调用了,然后经过Handler布告到UI或其余线程。小编写了一个AysncTask代替库AsyncTaskScheduler,完成了通过线程池调用和单个线程调用的有血有肉方法,里面有切实可行的兑现格局。

并发的学习...

本文由8535.com-新浦京娱乐场官网|欢迎您发布于计算机网络,转载请注明出处:Callable和Future、FutureTask的采纳,callablefuturetask

关键词:

最火资讯