一份针对于新手的多线程实践

 

前言

前段时间在某个第三方平台看到我写作字数居然突破了 10W 字,难以想象高中 800 字作文我都得巧妙的利用换行来完成(懂的人肯定也干过😏)。

干了这行养成了一个习惯:能撸码验证的事情都自己验证一遍。

于是在上周五通宵加班的空余时间写了一个工具:

https://github.com/crossoverJie/NOWS

利用 SpringBoot 只需要一行命令即可统计自己写了多少个字。

java -jar nows-0.0.1-SNAPSHOT.jar /xx/Hexo/source/_posts

传入需要扫描的文章目录即可输出结果(目前只支持 .md 结尾 Markdown 文件)

当然结果看个乐就行(40 几万字),因为早期的博客我喜欢大篇的贴代码,还有一些英文单词也没有过滤,所以导致结果相差较大。

如果仅仅只是中文文字统计肯定是准的,并且该工具内置灵活的扩展方式,使用者可以自定义统计策略,具体请看后文。

其实这个工具挺简单的,代码量也少,没有多少可以值得拿出来讲的。但经过我回忆不管是面试还是和网友们交流都发现一个普遍的现象:

大部分新手开发都会去看多线程、但几乎都没有相关的实践。甚至有些都不知道多线程拿来在实际开发中有什么用。

为此我想基于这个简单的工具为这类朋友带来一个可实践、易理解的多线程案例。

至少可以让你知道:

  • 为什么需要多线程?
  • 怎么实现一个多线程程序?
  • 多线程带来的问题及解决方案?

单线程统计

再谈多线程之前先来聊聊单线程如何实现。

本次的需求也很简单,只是需要扫描一个目录读取下面的所有文件即可。

所有我们的实现有以下几步:

  • 读取某个目录下的所有文件。
  • 将所有文件的路径保持到内存。
  • 遍历所有的文件挨个读取文本记录字数即可。

先来看前两个如何实现,并且当扫描到目录时需要继续读取当前目录下的文件。

这样的场景就非常适合递归:

    public List<String> getAllFile(String path){          File f = new File(path) ;         File[] files = f.listFiles();         for (File file : files) {             if (file.isDirectory()){                 String directoryPath = file.getPath();                 getAllFile(directoryPath);             }else {                 String filePath = file.getPath();                 if (!filePath.endsWith(".md")){                     continue;                 }                 allFile.add(filePath) ;             }         }          return allFile ;     } }

读取之后将文件的路径保持到一个集合中。

需要注意的是这个递归次数需要控制下,避免出现栈溢出(StackOverflow)。

最后读取文件内容则是使用 Java8 中的流来进行读取,这样代码可以更简洁:

Stream<String> stringStream = Files.lines(Paths.get(path), StandardCharsets.UTF_8); List<String> collect = stringStream.collect(Collectors.toList());

接下来便是读取字数,同时要过滤一些特殊文本(比如我想过滤掉所有的空格、换行、超链接等)。

扩展能力

简单处理可在上面的代码中遍历 collect 然后把其中需要过滤的内容替换为空就行。

但每个人的想法可能都不一样。比如我只想过滤掉空格、换行、超链接就行了,但有些人需要去掉其中所有的英文单词,甚至换行还得留着(就像写作文一样可以充字数)。

所有这就需要一个比较灵活的处理方式。

看过上文

这样一个简单的统计字数的工具就完成了。

多线程模式

在我本地一共就几十篇博客的条件下执行一次还是很快的,但如果我们的文件是几万、几十万甚至上百万呢。

虽然功能可以实现,但可以想象这样的耗时绝对是成倍的增加。

这时多线程就发挥优势了,由多个线程分别去读取文件最后汇总结果即可。

这样实现的过程就变为:

多线程带来的问题

也不是使用多线程就万事大吉了,先来看看第一个问题:共享资源。

简单来说就是怎么保证多线程和单线程统计的总字数是一致的。

基于我本地的环境先看看单线程运行的结果:

总计为:414142 字。

接下来换为多线程的方式:

List<String> allFile = scannerFile.getAllFile(strings[0]); logger.info("allFile size=[{}]",allFile.size()); for (String msg : allFile) {     executorService.execute(new ScanNumTask(msg,filterProcessManager)); }  public class ScanNumTask implements 
                        
关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信