Java 多线程读取文件并统计词频 实例 出神入化的《ThreadPoolExecutor》
重在展示多线程ThreadPoolExecutor的使用,和线程同步器CountDownLatch,以及相关CAS的原子操作和线程安全的Map/队列。
ThreadPool主线程
1 import java.io.BufferedWriter;
2 import java.io.File;
3 import java.io.FileWriter;
4 import java.util.*;
5 import java.util.concurrent.*;
6 import java.util.concurrent.atomic.AtomicInteger;
7 import java.util.concurrent.atomic.AtomicReferenceArray;
8
9 /**
10 * ClassName: ThreadPool
11 * Description:
12 * date: 2021/1/16 18:24
13 *
14 * @author hewei
15 */
16 public class ThreadPool {
17 /**存储词的队列**/
18 private static ArrayBlockingQueue<String> oneWordQueue = new ArrayBlockingQueue<String>(Integer.MAX_VALUE / 4);
19 /**存储词的次数**/
20 private static ConcurrentHashMap<String, AtomicInteger> wordCount = new ConcurrentHashMap<String, AtomicInteger>();
21 /**判断中英文的正则**/
22 private static String[] englishOrChinaWordCompile = {"[a-zA-Z]+", "[\\u4e00-\\u9fa5]"};
23 private static long waitTimeSecond = 5;
24 /**已知会创建10个线程池**/
25 private static CountDownLatch countDownLatch = new CountDownLatch(10);
26 /**存储词的次数排序**/
27 private static AtomicReferenceArray wordCountArray=new AtomicReferenceArray<String>(Integer.MAX_VALUE/16);
28
29 public static void main(String[] args) {
30 BlockingQueue<Runnable> blockingQueue = new LinkedBlockingDeque<>(10000);
31 ThreadPoolExecutor readFilePool = new ThreadPoolExecutor(5, 5,
32 waitTimeSecond, TimeUnit.SECONDS, blockingQueue, new UserThreadFactory("Study-WordCountReadFile-"),
33 new UserRejectHandler());
34 //executor.allowCoreThreadTimeOut(true);
35 Long beginTime = System.currentTimeMillis();
36 //读取D盘的文件
37 File file = new File("E:\\tmp");
38 if (file.isDirectory()) {
39 File[] files = file.listFiles();
40 // 定义文件类型
41 for (File one : files) {
42 String fileName = one.getName();
43 readFilePool.execute(new WordCountReadFileTask(countDownLatch, "E:\\tmp\\" + fileName, oneWordQueue, englishOrChinaWordCompile));
44 }
45 }
46 ThreadPoolExecutor sortWordPool = new ThreadPoolExecutor(5, 5,
47 waitTimeSecond, TimeUnit.SECONDS, blockingQueue, new UserThreadFactory("Study-WordCount-"),
48 new UserRejectHandler());
49 //executor1.allowCoreThreadTimeOut(true);
50 for (int i = 0; i < 5; i++) {
51 sortWordPool.execute(new WordCountTask(countDownLatch, wordCount, oneWordQueue, waitTimeSecond,null));
52 }
53 try {
54 countDownLatch.await();
55 readFilePool.shutdown();
56 sortWordPool.shutdown();
57 // 写出到文件
58 List<Map.Entry<String, AtomicInteger>> list = new ArrayList(wordCount.entrySet());
59 Comparator com = new Comparator<Map.Entry<String, AtomicInteger>>(){
60 @Override
61 public int compare(Map.Entry<String, AtomicInteger> o1, Map.Entry<String, AtomicInteger> o2) {
62 return ((Integer)o2.getValue().get()).compareTo((Integer) o1.getValue().get());
63 }
64 };
65 list.sort(com);
66 // 写出到文件
67 BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\read.txt"));
68 for(int i=0;i<list.size();i++){
69 if(i<10) {
70 System.out.println("单词 " + list.get(i).getKey() + ",次数 " + list.get(i).getValue());
71 }
72 bw.write("单词 "+ list.get(i).getKey()+",次数 "+ list.get(i).getValue());
73 bw.newLine();
74 }
75 bw.flush();
76 bw.close();
77 } catch (Exception e) {
78 e.printStackTrace();
79 }
80 }
81 }
UserThreadFactory
1 import java.util.concurrent.ThreadFactory;
2 import java.util.concurrent.atomic.AtomicInteger;
3
4 /**
5 * ClassName: UserThreadFactory
6 * Description:自定义线程创建工厂
7 * date: 2021/1/16 18:26
8 *
9 * @author hewei
10 */
11 public class UserThreadFactory implements ThreadFactory {
12 /**
13 * 自定义线程名称前缀
14 **/
15 private final String prefixName;
16 /**
17 * 线程计数器 从1开始
18 */
19 private final AtomicInteger threadNumber = new AtomicInteger(1);
20
21 public UserThreadFactory(String prefixName) {
22 this.prefixName = prefixName;
23 }
24
25 @Override
26 public Thread newThread(Runnable runnable) {
27 //创建线程
28 String name = prefixName + threadNumber.getAndIncrement();
29 return new WorkThread(runnable,name);
30 }
31 /**
32 *自定义工作线程,定义线程名称有助于对jvm问题排查
33 */
34 class WorkThread extends Thread {
35 /**
36 * 线程名称
37 */
38 private String name;
39
40 /**
41 * @param target 执行的方法
42 * @param name 线程的名称
43 */
44 public WorkThread(Runnable target, String name) {
45 super(target);
46 super.setName(name);
47 this.name=name;
48 System.out.println("创建:"+name);
49 }
50
51 @Override
52 public void run() {
53 try {
54 /**
55 * super.run()等同于target.run()
56 */
57 super.run();
58 } finally {
59 System.out.println("结束线程:" + name);
60 }
61 }
62 }
63 }
WordCountReadFileTask
1 import java.io.BufferedReader;
2 import java.io.FileReader;
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.concurrent.ArrayBlockingQueue;
6 import java.util.concurrent.CountDownLatch;
7 import java.util.regex.Matcher;
8 import java.util.regex.Pattern;
9
10 /**
11 * ClassName: WordCountTask
12 * Description:
13 * date: 2021/1/17 19:48
14 *
15 * @author hewei
16 */
17 public class WordCountReadFileTask implements Runnable {
18 private String filePathAndName;
19 private ArrayBlockingQueue<String> oneWordQueue;
20 private String[] englishOrChinaWordCompile;
21 private CountDownLatch countDownLatch;
22
23 public WordCountReadFileTask(CountDownLatch countDownLatch,String filePathAndName, ArrayBlockingQueue<String> oneWordQueue, String[] englishOrChinaWordCompile) {
24 this.countDownLatch=countDownLatch;
25 this.filePathAndName = filePathAndName;
26 this.oneWordQueue = oneWordQueue;
27 this.englishOrChinaWordCompile = englishOrChinaWordCompile;
28 }
29
30 @Override
31 public void run() {
32 try {
33 BufferedReader br = new BufferedReader(new FileReader(filePathAndName));
34 StringBuffer sb = new StringBuffer();
35 List<String> strList=new ArrayList<String>();
36 String line = "";
37 while((line=br.readLine())!=null){
38 sb.append(line);
39 /**
40 * 为了保证不超过Integer.max_value
41 */
42 if(sb.length()>50000000) {
43 strList.add(sb.toString());
44 /**
45 * 清空StringBuffer
46 * 1.delete,从到到尾
47 * 2.new 新的对象。但会丢弃老对象加速gc到来
48 * 3.setlength=0,不符合这里的场景
49 */
50 sb.delete(0,sb.length());
51 }
52 }
53 if(sb!=null){
54 strList.add(sb.toString());
55 }
56 br.close();
57 for(String words:strList) {
58 for (String oneCompile : englishOrChinaWordCompile) {
59 //正则
60 Pattern p = Pattern.compile(oneCompile);
61 Matcher matcher = p.matcher(words);
62 while (matcher.find()) {
63 /**
64 * 添加一个元素,如果队列满,则阻塞等待队列被消费腾出空间来
65 */
66 oneWordQueue.put(matcher.group());
67 }
68 }
69 }
70 } catch (Exception e) {
71 e.printStackTrace();
72 }finally {
73 countDownLatch.countDown();
74 }
75 }
76 }
WordCountTask
1 import java.io.BufferedReader;
2 import java.io.FileReader;
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.List;
6 import java.util.concurrent.ArrayBlockingQueue;
7 import java.util.concurrent.ConcurrentHashMap;
8 import java.util.concurrent.CountDownLatch;
9 import java.util.concurrent.TimeUnit;
10 import java.util.concurrent.atomic.AtomicInteger;
11 import java.util.concurrent.atomic.AtomicReferenceArray;
12 import java.util.regex.Matcher;
13 import java.util.regex.Pattern;
14
15 /**
16 * ClassName: WordCountTask
17 * Description:
18 * date: 2021/1/17 19:48
19 *
20 * @author hewei
21 */
22 public class WordCountTask implements Runnable {
23 private ArrayBlockingQueue<String> oneWordQueue;
24 private ConcurrentHashMap<String, AtomicInteger> wordCount;
25 private long waitTimeSecond;
26 private CountDownLatch countDownLatch;
27 private static AtomicReferenceArray wordCountArray;
28
29 public WordCountTask(CountDownLatch countDownLatch,ConcurrentHashMap<String,AtomicInteger> wordCount,
30 ArrayBlockingQueue<String> oneWordQueue,long waitTimeSecond,AtomicReferenceArray wordCountArray) {
31 this.wordCountArray=wordCountArray;
32 this.countDownLatch=countDownLatch;
33 this.oneWordQueue = oneWordQueue;
34 this.wordCount=wordCount;
35 this.waitTimeSecond=waitTimeSecond;
36 }
37
38 @Override
39 public void run() {
40 try {
41 String oneWord;
42 AtomicInteger nowCount;
43 while ((oneWord=oneWordQueue.poll(waitTimeSecond, TimeUnit.SECONDS))!=null) {
44 /**
45 * 循环从队列里取出元素,然后加入到map中
46 * 在加入map过程中,代码块会有指令重排问题。所以每一步都需要加判断。
47 * 所以需要每一个操作都要具有原子性。
48 */
49 if((nowCount=wordCount.get(oneWord))==null){
50 nowCount=new AtomicInteger(1);
51 AtomicInteger ifExistCount=wordCount.putIfAbsent(oneWord,nowCount);
52 if(ifExistCount!=null) {
53 ifExistCount.getAndIncrement();
54 }
55 }else{
56 nowCount.getAndIncrement();
57 }
58 /**
59 * 实时排序,该排序依赖线程安全
60 * 略
61 */
62 }
63 } catch (Exception e) {
64 e.printStackTrace();
65 }finally {
66 countDownLatch.countDown();
67 }
68 }
69 }
Java 多线程读取文件并统计词频 实例 出神入化的《ThreadPoolExecutor》的更多相关文章
- JAVA多线程读写文件范例
在写之前先声明,本文是基于之前在博客园网站上检索到的一份JAVA多线程读写文件的示例,我在写自己的程序时是在那位作者写的基础上做了改良,但已不记得原文的地址.如果有知情者,烦请帖出地址,我在此文上加入 ...
- JAVA本地读取文件,解决中文乱码问题
JAVA本地读取文件出现中文乱码,查阅一个大神的博客做一下记录 import java.io.BufferedInputStream;import java.io.BufferedReader;imp ...
- Java中读取文件
Java中读取文件,去除一些分隔符,保存在多维数组里面 public void readFile(String filePath) { File file=new File(filePath); Ar ...
- python(35):多线程读取文件
多线程读取文件: # _*_coding:utf-8_*_ import time, threading, ConfigParser ''' Reader类,继承threading.Thread @_ ...
- Java代码读取文件
用Java代码读取文件时,保持文件本来的格式(主要是保持换行),这点有时候比较重要.用代码实现也相当简单. private static void readFile() { StringBuilder ...
- Java实现读取文件
目录 Java实现读取文件 1.按字节读取文件内容 使用场景 2.按字符读取文件内容 使用场景 3.按行读取文件内容 使用场景 4.随机读取文件内容 使用场景 Java实现读取文件 1.按字节读取文件 ...
- Java方法读取文件内容
一.针对文件内容的读取,在平时的工作中想必是避免不了的操作,现在我将自己如何用java方法读取文件中内容总结如下:废话不多说,直接上代码: 1 public static void main(Stri ...
- Java多线程读取大文件
前言 今天是五一假期第一天,按理应该是快乐玩耍的日子,但是作为一个北漂到京师的开发人员,实在难想出去那玩耍.好玩的地方比较远,近处又感觉没意思.于是乎,闲着写篇文章,总结下昨天写的程序吧. 昨天下午朋 ...
- java 多线程下载文件 以及URLConnection和HttpURLConnection的区别
使用 HttpURLConnection 实现多线程下载文件 注意GET大写//http public class MultiThreadDownload { public static void m ...
随机推荐
- php curl的使用心得
php的curl有很多参数,整理一下其中的常用参数的作用 1.CURLOPT_SSL_VERIFYHOST 设置为 1 是检查服务器SSL证书中是否存在一个公用名(common name).译者注:公 ...
- expdp、impdp状态查看及中断方法
一.expdp状态查看及中断方法 1.查询expdp的job的名字 SQL> select job_name from dba_datapump_jobs; JOB_NAME---------- ...
- [日常摸鱼]bzoj2875[NOI2012]随机数生成器-矩阵快速幂
好裸的矩阵快速幂-然而我一开始居然构造不出矩阵- 平常两个的情况都是拿相邻两项放在矩阵里拿去递推的-然后我就一直构造不出来-其实把矩阵下面弄成1就好了啊orz #include<cstdio&g ...
- Web服务器-服务器开发-返回浏览器需要的页面 (3.3.2)
@ 目录 1.说明 2.代码 关于作者 1.说明 使用正则表达式,匹配客户端的请求头 获取到请求的路径 返回对应请求路径的文字 可以使用打开对应文件的方式去返回对应的文件 2.代码 from sock ...
- tep用户手册帮你从unittest过渡到pytest
unittest和pytest是Python的2个强大的测试框架,经常用来做UI自动化或接口自动化.unittest是PyCharm的默认集成工具,也是我们大多数人入门自动化的首选框架.pytest提 ...
- Geoserver 谷歌瓦片地图的使用 多级发布
下面,我来介绍一下如何在离线的情况下,在Geoserver 中配置出如同谷歌地图般绚丽的效果. 为了让大家有动力看我我接下来写的东西,我先把结果图给大伙儿展现一下: 正如上图所示,该地图是谷歌第四级的 ...
- GDI+中发生一般性错误 Winform Image.Save(mstream, ImageFormat.Png)引发
在处理图片时,读取本地图像文件,进行另存时发生GDI+中发生一般性错误 . 具体情况如下: 用OpenFileDialog打开图像文件,文件名为filename StreamReader sr = n ...
- 7.自定义ViewGroup-下滑抽屉
1.效果 2.思路 分析效果: 1.布局分为两部分,后面部分,前面部分,默认状态后面被挡住: 2.后面不可以滑动,前面可以滑动: 3.如果前面的布局本身是可以滑动的,那么当前面布局滑动到第一个时,后面 ...
- SpringBoot 内嵌容器的比较
Spring Boot内嵌容器支持Tomcat.Jetty.Undertow.为什么选择Undertow? 这里有一篇文章,时间 2017年1月26日发布的: 参考 Tomcat vs. Jetty ...
- java 多线程40个问题汇总(转)
java 多线程40个问题汇总,自己也记录一份,如有侵权,联系删除 ref from :http://www.cnblogs.com/xrq730/p/5060921.html 1.多线程作用 - 利 ...