技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152
注意之前咱们说的线程池队列中都是用的实现了Runnbale接口的线程,
这里咱们用的是实现了Callable接口的线程.
Callable和Runnbale一样代表着是线程任务,区别在于Callable有返回值并且可以抛出异常。
创建并启动有返回值的线程的步骤如下:
- 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且该call()方法有返回值。
- 将Callable实例传入FutureTask类。
- 使用FutureTask对象作为Thread对象的target创建并启动新线程。
- 调用FutureTask对象的get()方法来获得子线程结束后的返回值
这里咱们自己通过实现Callable接口来自己弄一个线程.
这个FutureTask这个类是,Callable这种方式实现线程的过程中很重要的一个类
执行线程,需要用这个类
执行一下看看,可以看到,因为上面都有2秒延迟,所以延迟后就打印出了一个7
可以看到这里00000接着就打印出来了,9是过了2秒打印出来的,也就说,这个延迟是
咱们的线程延迟的.
然后去看一下这个FutureTask这个类去
注意这个类中state是状态,然后可以看到这个状态有
NEW 新建线程
COMPLETING 线程执行完毕
NORMAL 线程就绪
EXCEPTIONAL 线程出现异常
CANCELLED 线程被取消
INTERRUPTING 线程正在被打断
INTERRUPTED 线程被打断.
这个callable是用来接收任务的
这个outcome这个是接收返回值的.
可以看到FutureTask的构造方法,callable,用来接收任务
然后接收到任务以后给个任务加个状态,是NEW也就是0这个状态
然后再看一下FutureTask他的run方法,
可以看到这里的c.call(),其实就是实现callable接口的时候,让实现的那个方法
可以看到执行完以后就把callable那个线程的返回值拿到了.
拿到以后,走了set(result)
把这个返回值赋值给了outcome
同时这里,设置结果的时候,就意味着,这个线程执行完了
这个时候就把状态设置为COMPLETING
然后设置返回结果以后,再把这个状态设置为NORMAL,也就是说这个线程又可以为其他任务进行服务了
然后,FutureTask,中还有个get()方法,
这个方法,COMPLETING这个是1
NOMARL是2
小于2的时候也就是,线程可能在执行中,这个时候就走
awaitDone进行线程等待
可以看到这里走了个死循环,等待什么呢?
这里等待可以看到,这里等待,也就是状态是2,也就是NORMAL的时候
状态是执行完毕的时候,就可以返回线程执行的结果了,否则的话就死循环一直等待.
等待执行完以后,再把线程的执行结果返回过去
这样就实现了了,对线程执行的等待,也就是,当调用FutureTask的get()方法的时候,会等
线程执行完毕以后,再返回执行结果
好了,有了上面的对Callable的理解,接下来我们用线程池,来执行一下,实现了
callable的线程任务
可以看到每个callable线程执行以后,最后我都会去get,获取执行结果,要注意
这里执行任务不是用的execute,这里用的submit,并且,执行这个任务以后,返回的是个
Future对象.
执行可以看到结果,因为我们队列大小是3,并且,这里,call中,sleep了2秒钟
所以,执行一下的结果就是,每当2秒以后,就会打印出一行信息,因为
每执行一个任务这里都会get一下.get的时候,就会等待线程执行完以后,也就是2秒以后,才会返回执行结果.
这样太慢了对吧,这样咱们可以这样
用个list,吧执行后返回的Future都记录下来,然后统一打印
这个时候,可以看到,会3个,3个的打印出来,这个是怎么回事呢?
是这样的,因为这里咱们线程池队列大小有3个,也就是同时可以有3个线程去执行任务,
这样同时会执行3个任务,也就是同时会有3个输出,也就是,同时会有3个任务在那里等待2秒,这样输出的时候
就是3个,3个一块输出的了.