java:线程池任务提交(Runnable、Callable、FutureTask)

任务的封装与执行过程

(注:下面所说的Runnable对象,Callable对象都是指实现了该接口的类的对象)

之前要交给线程执行的任务我们都把它封装在Runnable中。对于线程池而言,多了一种Callable的封装方式。

Runnable:其中的run()方法没有返回值。

①.Runnable对象可以直接扔给Thread创建线程实例,并且创建的线程实例与Runnable绑定,线程实例调用start()方法时,Runnable任务就开始真正在线程中执行。注意:如果直接调用run()方法而不调用start()方法,那么只是相当于普通的方法调用,并不会开启新的线程,程序只是在主线程中串行执行。

②.Runnable对象也可以直接扔给线程池对象的execute方法和submit方法,让线程池为其绑定池中的线程来执行。

③.Runnable对象也可以进一步封装成FutureTask对象之后再扔给线程池的execute方法和submit方法。

Callable:功能相比Runnable来说少很多,不能用来创建线程,也不能直接扔给线程池的execute方法。但是其中的call方法有返回值。

FutureTask:是对Runnable和Callable的进一步封装,并且这种任务是有返回值的,它的返回值存在FutureTask类的一个名叫outcome的数据成员中。(疑惑)那么为什么可以把没有返回值的Runnable也封装成FutureTask呢,马上我们会讨论这个问题。相比直接把Runnable和Callable扔给线程池,FutureTask的功能更多,它可以监视任务在池子中的状态。用Runnable和Callable创建FutureTask的方法稍有不同。

①.使用Callable来创建,由于call方法本身有返回值,这个返回值也就是Callable对象的返回值,于是可以把这个返回值当做FutureTask的返回值,也就是拿call方法的返回值去初始化outcome字段(是Object的引用,可以理解成引用的Future对象),这个真正初始化过程要在submit方法把任务扔给池子之后并且该任务在池子中分配到了线程并且在线程中执行完了产生了结果之后。但是在这一系列动作之前会有一个伪初始化,submit方法一旦提交任务到线程池马上会得到一个返回值(Future对象,用来指代刚才提交的任务的结果,相当于付钱买了商品但是没货了,暂时拿了一个票据,到了货再真的的取货,这个Future对象就相当于票据),submit方法不会真正等到上面的那一系列动作执行完才返回,所以需要使用这个任务执行结果的那些线程就可以拿着这个返回值(Future对象)去该怎么用就怎么用了。(之所以叫伪初始化,因为call方法也许还没有开始执行,任务还在线程池的任务队列中排队呢。)所以在创建FutureTask的时候只用给FutureTask的构造方法传一个Callable对象既可。源码中方法签名如下:

②.使用Runnable来创建(我们通常不这么干),正如上面所疑惑的那样,run方法没有返回值,也就是Runnable任务没有返回值,那么为什么用它封装的FutureTask却有了返回值了呢。原因在于这种方法创建的FutureTask对象并不是把run的返回值当成自己的返回值,而是在创建FutureTask对象时就已经手动指定了这个FutureTask对象的返回值了。若不希望FutureTask对象有真正意义上的返回值,我们可以在调用用FutureTask的构造方法时指定第二个参数为null,对应构造方法使用FutureTask<Void>。源码中方法签名如下:

原文参考:https://blog.csdn.net/qq_26963495/article/details/79015110

猜你喜欢

转载自blog.csdn.net/weixin_38750084/article/details/84801211