Java并发编程(1)- Callable、Future和FutureTask
2021/11/24 12:10:37
本文主要是介绍Java并发编程(1)- Callable、Future和FutureTask,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
撸过JavaSE(即Java基础技术栈)的小伙伴都知道,实现多线程有两种方式,一种是继承Thread,即extends Thread 然后实现其中的run()方法;另外一种是实现Runnable接口,即implements Runnable,然后实现其中的run()方法;仔细观察这两种方式,会发现这两者都不能返回线程异步执行完的结果,但在实际项目开发中却偶尔需要获取其中的返回结果,咋办嘞?于是乎Callable和Future就排上用场了,本文我们将对其做一番详尽的介绍!
还是先介绍下多线程的传统实现方式吧,如下代码所示:
public class ThreadUtil { public static void main(String[] args) throws Exception{ Thread thread=new Thread(new Runnable() { @Override public void run() { System.out.println("---子线程正在执行---"+Thread.currentThread().getName()); Map<String,Object> dataMap=Maps.newHashMap(); dataMap.put("id",10010); dataMap.put("name","steadyjack"); dataMap.put("nickName","多隆"); System.out.println("---子线程执行后得到的结果:"+dataMap); } }); try { thread.start(); }catch (Exception e){ e.printStackTrace(); } System.out.println("---主线程正在执行---"+Thread.currentThread().getName()); } }
在上述代码中,我们首先通过一个实现Runnable接口的匿名实现类创建了一个线程对象实例,即thread,并编写实现了其中run()方法的代码逻辑(而这就是该线程要执行的任务),主要是构造一个私有变量Map<String,Object>,并将相关的数据塞入进去。
点击运行该代码后,显而易见可以预测其运行结果:
从上述编写的代码以及运行结果来看,会发现如果我们想获取得到dataMap的内容是很困难的,因为run()方法的返回值为void;当然啦,也不是完全没有办法,在上面的条件下,如果想要获取到dataMap并做进一步的操作的话,则可以将dataMap定义为全局的共享变量,或者使用线程通信的方式来达到效果,如下所示为通过共享全局变量的方式:
public class ThreadUtil { private static final Map<String,Object> dataMap=Maps.newHashMap(); ……… }
之后就可以在该类的其他地方使用了!
但这种方式有个很明显的弊端,那就是多线程共享、并发访问可能会出现安全性问题,即如果开启10个线程,每个线程需要对dataMap里头的key,即id 加1,在高并发的情况下其最终的运行效果很可能不一定是 10020 (因为初始值为10010,每个线程加1次,10个线程下来就是加10次,理想情况下为10020),如下图所示:
但有时候我们在项目里头既要用到异步(为了解耦)、也想要获取异步执行的结果,可以说是“鱼和熊掌皆想兼得”:
于是乎这个重任就落到了Callable和Future身上了,这是JDK从1.5版本开始就已经提供了,可以通过它们实现在任务异步执行完毕之后得到任务的执行结果。
看到这里,可能有些小伙伴会发问:为什么通过Callable就可以获取到线程异步执行的结果呢?这一切还得回归到源码身上,如下所示为Callable的定义:
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; }
会发现它跟Runnable一样都是接口,但区别在于创建Callable时可以传入一个泛型V,而这个泛型类型V会发现真是call()方法执行后返回的结果(call()方法的作用类似于run()方法,反正都是指一个线程要执行的任务),OK,到此谜底就解开了!
那么怎么使用Callable呢?在Java里面可以通过调用ExecutorService类里面的相关API来使用Callable,如下图所示:
仔细观察上图,会发现如果想要获取线程执行Callable类型任务后的结果时,需要通过Future进行获取,那么Future为何物呢?
更多请见:http://www.mark-to-win.com/tutorial/51113.html
这篇关于Java并发编程(1)- Callable、Future和FutureTask的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-29RocketMQ底层原理资料详解:新手入门教程
- 2024-11-29RocketMQ源码资料解析与入门教程
- 2024-11-29[开源]6.1K star!这款电视直播源神器真的太赞啦!
- 2024-11-29HTTP压缩入门教程:轻松提升网页加载速度
- 2024-11-29JWT开发入门指南
- 2024-11-28知识管理革命:文档软件的新玩法了解一下!
- 2024-11-28低代码应用课程:新手入门全攻略
- 2024-11-28哪些办公软件适合团队协作,且能够清晰记录每个阶段的工作进展?
- 2024-11-28全栈低代码开发课程:零基础入门到初级实战
- 2024-11-28拖动排序课程:轻松掌握课程拖动排序功能