零基础学习java------30---------wordCount案例(涉及到第三种多线程callable)
知识补充:多线程的第三种方式
来源:http://www.threadworld.cn/archives/39.html
创建线程的两种方式,一种是直接继承Thread,另外一种就是实现Runnable接口。这两种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。
一、Runnable接口
先看一下java.lang.Runnable吧,它是一个接口,在它里面只声明了一个run()方法:
由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。
二、Callable接口
Callable接口位于java.util.concurrent包下,在它里面也只声明了一个方法,只不过这个方法叫做call()。
可以看到,这是一个泛型接口,call()函数返回的类型就是传递进来的V类型。Callable接口可以看作是Runnable接口的补充,call方法带有返回值,并且可以抛出异常。
三、FutureTask类
如何获取Callable的返回结果呢?一般是通过FutureTask这个中间媒介来实现的。整体的流程是这样的:
把Callable实例当作参数,生成一个FutureTask的对象,然后把这个对象当作一个Runnable,作为参数另起线程。
3.1 FutureTask的结构
3.2 FutureTask的启动
由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行
四、Future接口
FutureTask继承体系中的核心接口是Future。Future的核心思想是:一个方法,计算过程可能非常耗时,等待方法返回,显然不明智。可以在调用方法的时候,立马返回一个Future,可以通过Future这个数据结构去控制方法f的计算过程。
这里的控制包括:
get方法:获取计算结果(如果还没计算完,也是必须等待的)
cancel方法:还没计算完,可以取消计算过程
isDone方法:判断是否计算完
isCancelled方法:判断计算是否被取消
例子
public class ThreadMain { public static void main(String[] args) throws Exception, ExecutionException { ThreadTest threadTest = new ThreadTest();//线程任务 // FutureTask接收线程的返回数据 FutureTask<String> f = new FutureTask<>(threadTest); Thread thread = new Thread(f); thread.start(); String res = f.get(); System.out.println(res); } } class ThreadTest implements Callable<String>{ @Override public String call() throws Exception { return "hello"; } }
一. 单词统计案例
使用多线程,不同的线程统计不同的文件中的单词的个数,将统计的结果数据写入到指定的中间文件中进行单词个数的汇总统计 。
客户端:
public class MyClient implements Callable<String>{ //不同线程处理不同的文件 String localFilePath ; public MyClient(String localFilePath) { super(); this.localFilePath = localFilePath; } public static final String KEY = "天王盖地虎"; public static final String PATH = "E:/javafile/wc_server.jar"; @SuppressWarnings("unused") private String task() throws Exception{ String res = null; Socket socket = new Socket("127.0.0.1",8888); ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); //1 发送身份校验 oos.writeObject(KEY); //2 接收校验结果 boolean b = (boolean)ois.readObject(); if(b) {//校验成功 System.out.println("校验成功"); //3 发送服务端存储jar包的路径 oos.writeObject(PATH); //4 往服务端发送jar包 // 4.1 读取本地需要的jar包 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:/javafile/wc.jar")); byte[] bs = new byte[1024]; int len; while((len = bis.read(bs))!= -1) { // 4.2 利用网络流发送此jar包 oos.write(bs,0,len); } oos.flush(); bis.close(); // 往服务端发送执行命令 String cmd = "java -jar "+PATH+" " +localFilePath; oos.writeObject(cmd); // 接收服务端jar程序执行的结果 res = (String)ois.readObject(); // System.out.println(res); }else { System.out.println("校验失败"); } socket.close(); return res; } @Override public String call() throws Exception { String res = task(); return res; } }
服务端
public class MyServer { public static final String KEY = "天王盖地虎"; public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(8888); while(true) { Socket socket = ss.accept(); OutputStream os = socket.getOutputStream(); InputStream in = socket.getInputStream(); ObjectInputStream ois = new ObjectInputStream(in); ObjectOutputStream oos = new ObjectOutputStream(os); //接收客户端发送的身份校验 String str = (String)ois.readObject(); //校验成功 if(KEY.equals(str)) { oos.writeObject(true); // 接收路径 String path = (String)ois.readObject(); // 接收jar包,并写入指定的路径 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(path)); byte[] bs = new byte[1024]; int len = 0; while((len = ois.read(bs)) != -1) { bos.write(bs,0,len); } bos.flush(); bos.close(); // 接收执行命令 String cmd = (String)ois.readObject(); Runtime runtime = Runtime.getRuntime(); Process p = runtime.exec(cmd); InputStream inputStream = p.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); String line = null; StringBuilder res = new StringBuilder(); while((line = br.readLine()) != null) { res.append(line+"\r\n"); } // 将结果返回给客户端 oos.writeObject(res.toString()); oos.flush(); // 校验失败 }else { //将结果返回到客户端 oos.writeObject(false); } } } }
多线程统计结果
public class TestClient { public static void main(String[] args) throws Exception { // 创建第一个线程任务 MyClient m1 = new MyClient("E:/javafile/wc1.txt"); FutureTask<String> f1 = new FutureTask<>(m1); new Thread(f1).start(); String res1 = f1.get(); // System.out.println("线程1的结果:"+"/r/n"+ res1); // 创建第二个线程任务 MyClient m2 = new MyClient("E:/javafile/wc2.txt"); FutureTask<String> f2 = new FutureTask<>(m2); new Thread(f2).start(); String res2 = f2.get(); // System.out.println("线程2的结果:" +res2); //结果数据的汇总 ---> 写到中间结果 //将结果数据追加到指定的文件中 BufferedWriter bw = new BufferedWriter(new FileWriter(new File("E:/javafile/res.res"), true)); bw.write(res1); bw.write(res2, 0, res2.length()-2); //bw.write(res2); bw.close(); //统计结果数据 Map<String,Integer> map = new HashMap<>() ; BufferedReader br = new BufferedReader(new FileReader("E:/javafile/res.res")); String line = null ; while((line = br.readLine())!=null){ System.out.println(line); String[] split = line.split(":"); String word = split[0]; int num = Integer.parseInt(split[1]); Integer num2 = map.getOrDefault(word, 0); num2+=num; map.put(word, num2); } Set<Entry<String, Integer>> entrySet = map.entrySet(); for (Entry<String, Integer> entry : entrySet) { System.out.println(entry); } } }
原文地址:https://www.cnblogs.com/jj1106/p/11575599.html
- 海量数据处理利器之布隆过滤器
- ORM查询语言(OQL)简介--概念篇
- Discuz! 任意文件删除漏洞重现及分析
- .NET DLR 上的IronScheme 语言互操作&&IronScheme控制台输入中文的问题
- Java中Map相关的6大问题——每个开发人员都要注意
- android service 学习(下)
- 混淆漏洞CVE-2017-0213技术分析
- android service 学习(上)
- 黑帽SEO剖析之隐身篇
- Java中如何判断一个字符串是Java代码还是英文呢?
- 将复杂查询写到SQL配置文件--SOD框架的SQL-MAP技术简介
- Java中实现找到两个数组交集的2种方法,开发实用
- Java Web中JSP的include 指令知识点总结——每日一语法学习
- Java反序列化漏洞从理解到实践
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Android实现音乐播放器锁屏页
- android studio3.3.1代码提示忽略大小写的设置
- Ascgen2可以把图片变成文字的小工具
- 解决android studio卡顿,提升studio运行速度的方法
- Android物理键盘事件解析
- AndroidQ(10)分区存储完美适配方法
- (全局快捷键工具)Power Keys彻底提升码字效率?
- android自定义view实现钟表效果
- 教你如何用OpenVZ限制虚拟机硬盘IO速度
- Android自定义控件实现短信验证码自动填充
- android studio 3.6.1升级后如何处理 flutter问题
- Android项目迁移到AndroidX的方法步骤
- Android中layer-list基本使用详解
- Android Studio中主题样式的使用方法详解
- android点击无效验证的解决方法