Java▲Java多线程带返回值的Callable接口( 二 )


好了 , 我们通过上面案例在回到Thread类和Callable类来看 , 这两个对象之间有没有中间商呢?
从上图中我们发现 , Threa的有参构造都是Runnable接口的 。 那么 , 有没有一个类既实现了Runnable接口又实现了Callable接口呢?如果有这样的一个类存在的话 , callable就与Thread类产生了关系 , 就可以使用了 。 我们来看看Runnable接口的API吧
我们可以已知的子类有个RunnableFuture<V> 。 这个接口的形式和我们Callable接口的形式很像啊 , 如下图:
我们从上图对比中可以看到 , 两个接口中的V都是方法返回值的类型 。 那么Callable和Thread两个类之间的桥梁就是这个类(RunnableFuture)或者是这个类的子类呢?我们接着来看看这个对象的子类 。
其中SwingWorker这个我们不用看 。 这个是图形化的Swing相关的 。 我们不用 , 那么我们就来看看FutureTask这个类:
从这个类中 , 我们可以看到其实现了Runnable接口 , 在构造器中 , 我们可以看到:
FutureTask(Callable<V> callable)
创建一个 FutureTask, 它将在运行时执行给定的 Callable。
如下图:
这个类是不是既有Callable接口又有Runnable接口了?这个就是我们的中间类 。
所以 , 我们通过上面分析就可以得到下图的关系:
这种就是设计模式中的适配器模式(PS:在后面 , 凯哥会重新分享23种设计模式的) 。 在Java中的中间商是不会赚取差价的 , 放心 。 O(∩_∩)O
三:callable怎么使用及怎么获取返回值知道了Callable的设计思路之后 , 那么我们怎么来使用呢?
步骤:
1:同样创建一个类实现Callable接口;
2:通过futureTask类使用其传递Callable接口作为参数的有参构造方法;
3:使用thread的有参构造;
4:t1.start()启动线程
5:启动线程后 , 通过futureTask.get()方法获取到线程的返回值 。
如下图:
我们来查看运行结果:
进入了callable接口且获取到了返回值:1024.说明callable的使用正确了 。
需要注意:futrueTask.get()方法放到最后 , 这样就不会影响主线程了 。 如果get方法放在前面的话 , 会造成主线程阻塞 , 等到futrueTask运行完成之后 , 才继续执行自己的逻辑 。 这样就失去了开启线程的意义了!!!
四:多个线程同时调用结果
【Java▲Java多线程带返回值的Callable接口】我们可以看到t1和t2都start了 , 说明两个线程都启动了 。 而且都是用的是同一个futureTask对象 。 问题:MyThread3中的call方法会被调用几次呢?


推荐阅读