这两天写了一个app,就是统计一堆文本文件里中,出现频率最高的一些单词。
eg,找出某个文件夹下的所有文件中出现频率最高的100个单词
整体思路:肯定是用多线程去读取,要是一个线程的话会很慢的。
1 多个线程同时去读,将读到的单词保存到自己的线程中
2 多个线程将单词汇总到主线程
3 主线程合并每个线程读到的单词
4 主线程找出频率最高的100个
ps:题外话; 并不是使用的线程越多就越快,这里面有很多原因的,简单的说几个原因
(1)有IT经验的都知道,一个cpu在某一个时刻只能跑一个线程,所以对于现在的电脑或者服务器至少是双核的,最多的话同时跑两个线程,当然如果真的跑两个线程的话不是不可以,但是依据我的经验以及一些服务器的源码,都是跑电脑的cpu数目+1个线程,例如双核就跑3个,四核跑5个(本人理解较浅,欢迎拍砖)
(2)创建线程也是需要开销的,所以线程创建多了,开销自然而然的就打了,所以java的concurrent包里有cachepool以及fixpool等线程池,但是还是有开销的。
(3)自己写个程序,然后改变线程数目,跑跑看……
具体设计:
对于步骤1: 采用java concurrent包里的线程池来创建线程,打算跑3个线程,每个线程里有个map,存储单词,以及其出现的次数
对于步骤2: 使用concurrent包里的CountDownLatch类来 通知主线程去获取子线程的map
对于步骤3:就是将子线程的每个Map合并到主线程里的一个大map中,若有相同的单词,则合并,相加其出现的频率次数
对于步骤4:找出频率最高的前多少个,我打算使用最小堆来实现,比如前100个,就一直构建大小为100的最小堆
或者不用CountDownLatch,采用concurrent 中的Future + ExecutorService
其他设计:
1 每个子线程共同使用一个map,这样就不用主线程合并了。(想法很好,但是存在一个线程安全的问题,对于hashmap它是不安全的,虽说cuConcurrentHashMap<K,V>,但是他的效率实不是很高,因为有一个线程使用它,其他的线程就必须等待!这样不如每个线程里有有一个自己的Map,最终会总到主线程就ok了)
2 使用必须使用一个最小堆找出前100个,这个纯属于我得个人想法,因为比较单词不会很多,你用一个排序算法,可以使用java里collections.sort 这个方法,他的复杂度是nlogn级别的,也是很快的,我只所以使用堆是因为 堆占用的内存比较小,只是存储100个节点
还上不上代码?有点纠结……因为代码没了还要从新写一份……
简单写写吧……下篇见!