2024年5月3日
今天心情不错,写一篇多线程开发的文章过过瘾。 话不多说,问题如下
利用多线程读取文件中的所有单词,统计每个单词出现的次数。
一看就知道问题很简单,话不多说代码如下,其中的很多代码我们都会一个一个的解析
java"> public static void main(String[] args) throws FileNotFoundException {ThreadPoolExecutor executorService = new ThreadPoolExecutor(20, // 核心线程数量20, //最大线程数60, //空闲临时线程最大存活时间(数值)TimeUnit.SECONDS,//空闲临时线程最大存活时间(单位)new ArrayBlockingQueue<>(1_000_000_00),//任务队列,也就是一个堵塞队列,也可以使用LinkedBlockingQueue这个阻塞队列Executors.defaultThreadFactory(),//用线程池工具类Executors创建线程的工厂new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略中其中一个,丢弃任务并抛出RejectedExecutionException);
Map<String, Integer> hashMap = new HashMap<>();File file = new File("C:\Users\Desktop\the_text_book.txt");
System.out.println(executorService.getActiveCount());
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {String line;while ((line = bufferedReader.readLine()) != null) {String[] s = line.split(" ");if (s.length == 0) {continue;}executorService.submit(() -> {List<String> results = Arrays.asList(s);results.forEach(x -> {if (!(Objects.equals(x, "") || x == null)) {if (hashMap.containsKey(x)) {hashMap.put(x, hashMap.get(x) + 1);} else {hashMap.put(x, 1);}}});});}} catch (Exception e) {e.printStackTrace();}
while (true) {if (executorService.getActiveCount() == 0) {hashMap.forEach((k, v) -> {System.out.println(k + " " + v);});executorService.shutdown();break;}}}
创建线程池
java">ThreadPoolExecutor executorService = new ThreadPoolExecutor(20, // 核心线程数量20, //最大线程数60, //空闲临时线程最大存活时间(数值)TimeUnit.SECONDS,//空闲临时线程最大存活时间(单位)new ArrayBlockingQueue<>(1_000_000_00),//任务队列,也就是一个堵塞队列,也可以使用LinkedBlockingQueue这个阻塞队列Executors.defaultThreadFactory(),//用线程池工具类Executors创建线程的工厂new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略中其中一个,丢弃任务并抛出RejectedExecutionException);
如果你已经是一名稍微有点年头的开发者,你肯定知道怎么写创建线程池的。说句题外话,如果是使用的把配置信息交给框架自动配置的开发者,可以将线程池也放到组件容器中,比如Spring框架就可以这么用。
获取输出结果
java"> while (true) {if (executorService.getActiveCount() == 0) {hashMap.forEach((k, v) -> {System.out.println(k + " " + v);});executorService.shutdown();break;}}
因为使用了线程池,所以如果需要查看最后的效果,我可能会这么写:最后写一个while循环阻塞掉主线程,知道拿到对应结果(使用的是自定义线程池的API)
如果不想阻塞主线程,可以尝试使用别的方式,比如说使用Java8的API,CompletableFuture类进行实现,这个有一个方式是*allOf() *,该方法可以做到让全部的CompletableFuture任务都完成后再进行后续输出,笔者认为这个是通过创建一个异步线程/子线程来专门用于某一行代码的实现,就可以不使用阻塞线程的代码了,实现的代码如下:
java"> // 创建CompletableFuture,并将任务提交给线程池futureList.add(CompletableFuture.supplyAsync(() -> {List<String> results = Arrays.asList(s);results.forEach(x -> {if (!(Objects.equals(x, "") || x == null)) {if (hashMap.containsKey(x)) {hashMap.put(x, hashMap.get(x) + 1);} else {hashMap.put(x, 1);}}});return null;}, executorService));}CompletableFuture.allOf(futureList.toArray(futureList.toArray(new CompletableFuture[0]))).whenComplete((v, th) -> {hashMap.forEach((k, value) -> {System.out.println(k + " " + value);});}).join();
这样就可以在不阻塞主线程的情况下实现效果了
不过有一件事我也不是很明白,交给阅读这篇文章的你,我使用了ConcurrentHashMap和不使用ConcurrentHashMap的情况下,效果一样没有问题,在写这篇文章的时候我也一直没搞明白<3;
希望能对你有所帮助;
最终代码
偶对了,为了方便大家直接使用我就把代码直接完全贴一份到博客里面吧
java">public static void main(String[] args) throws FileNotFoundException {ThreadPoolExecutor executorService = new ThreadPoolExecutor(20, // 核心线程数量20, //最大线程数60, //空闲临时线程最大存活时间(数值)TimeUnit.SECONDS,//空闲临时线程最大存活时间(单位)new ArrayBlockingQueue<>(1_000_000_00),//任务队列,也就是一个堵塞队列,也可以使用LinkedBlockingQueue这个阻塞队列Executors.defaultThreadFactory(),//用线程池工具类Executors创建线程的工厂new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略中其中一个,丢弃任务并抛出RejectedExecutionException);
Map<String, Integer> hashMap = new ConcurrentHashMap<>();File file = new File("C:\Users\Desktop\the_text_book.txt");
System.out.println(executorService.getActiveCount());
List<CompletableFuture> futureList = new ArrayList<>();try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {String line;while ((line = bufferedReader.readLine()) != null) {String[] s = line.split(" ");if (s.length == 0) {continue;}// 创建CompletableFuture,并将任务提交给线程池futureList.add(CompletableFuture.supplyAsync(() -> {List<String> results = Arrays.asList(s);results.forEach(x -> {if (!(Objects.equals(x, "") || x == null)) {if (hashMap.containsKey(x)) {hashMap.put(x, hashMap.get(x) + 1);} else {hashMap.put(x, 1);}}});return null;}, executorService));}CompletableFuture.allOf(futureList.toArray(futureList.toArray(new CompletableFuture[0]))).whenComplete((v, th) -> {hashMap.forEach((k, value) -> {System.out.println(k + " " + value);});}).join();} catch (Exception e) {e.printStackTrace();}
}