在我看来,线程有时会结束,然后才能对所有想要的单词或字符进行计数.是因为当while(true)循环中断时,这些线程超出范围?
我已经从我的问题的一部分中包含了代码:
private void countText() { try { reader = new BufferedReader(new FileReader("this.txt")); while (true) { final String line = reader.readLine(); if(line == null) {break;} lines++; new Thread(new Runnable() {public void run() {chars += characterCounter(line);}}).start(); new Thread(new Runnable() {public void run() {words += wordCounter(line);}}).start(); println(line); } } catch(IOException ex) {return;} }
(子问题:这是我第一次询问某些东西和发布的代码,我不想使用StackOverflow代替谷歌和维基百科,我担心这不是一个适当的问题,我试图使问题更一般,所以我不只是要求帮助我的代码…但是,另一个网站,这种问题可能更适合?)
解决方法
我想你是多线程的这个代码学习线程,而不是加速计数字,但这是一个非常低效的方式使用线程.您每行创建两个线程 – 一千行线文件的两千线程.创建线程(在现代JVM中)使用操作系统资源,通常相当昂贵.当两个 – 更不用说两千线程必须访问共享资源(例如你的字符和单词计数器)时,所产生的内存争用也会伤害性能.
使计数器变量同步为Chris Kimpton suggests或Atomic为WMR suggests可能会修复代码,但也会使竞争的影响更糟.我确定它会比单线程算法慢.
我建议只有一个长寿命的线程,它照顾着chars,一个用于单词,每个线程都有一个工作队列,您可以在每次要添加新的数字时向其提交作业.这样只有一个线程正在写入每个变量,如果您对设计进行了更改,那么更明确的是谁负责什么.它也会更快,因为没有内存争用,你不会在紧缩的循环中创建数百个线程.
读取文件中的所有行后,等待所有线程完成之后,才能真正打印出计数器的值,否则丢失尚未完成的线程的更新也很重要.使用您当前的设计,您将必须构建一个您创建的线程的大列表,并通过它来完成它们的检查,以确定它们全部死亡.使用队列和工作线程设计,您可以告诉每个线程排除队列,然后等待直到完成.
Java(从1.5及更高版本)使这种设计非常容易实现:查看java.util.concurrent.Executors.newSingleThreadExecutor.它还使以后更容易添加更多并发(假设正确的锁定等等),因为您只需切换到线程池,而不是单线程.