2011-12-08 48 views
4

我做了一个程序来计算单个文件的字数, ,但我怎样才能修改我的程序,因此它给出了所有文件(作为一个值)的字的总量。多线程 - 计算来自多个文件的字的总量

我的代码如下所示:

public class WordCount implements Runnable 
{ 
    public WordCount(String filename) 
    { 
     this.filename = filename; 
    } 

    public void run() 
    { 
     int count = 0; 
     try 
     { 
     Scanner in = new Scanner(new File(filename)); 

     while (in.hasNext()) 
     { 
      in.next(); 
      count++; 
     } 
     System.out.println(filename + ": " + count); 
     } 
     catch (FileNotFoundException e) 
     { 
     System.out.println(filename + " blev ikke fundet."); 
     } 
    } 
    private String filename; 
} 

与主级:

public class Main 
{ 

    public static void main(String args[]) 
    { 
     for (String filename : args) 
     { 
     Runnable tester = new WordCount(filename); 

     Thread t = new Thread(tester); 
     t.start(); 
     } 
    } 
} 

,以及如何避免竞争条件? 谢谢你的帮助。

+1

什么样的竞赛条件? 我也看不到你在哪里添加不同文件的字数。 – zmbq

+0

你想要一个runnable /文件,还是只想让特定的runnable循环遍历所有文件?多线程的评论使这成为一个令人困惑的问题 – Robin

+0

我现在添加了我的主类。 – Chris

回答

0

您可以创建一个带有同步任务队列的线程池,该任务队列将包含您希望为其计算所有文件的所有文件。

当您的线程池工作人员联机时,他们可以要求任务队列计算一个文件。 工人完成他们的工作后,他们可以通知他们的最终号码的主线程。

主线程将有一个同步的通知方法,将所有工作线程的结果相加。

希望这会有所帮助。

+0

谢谢你,我想我是不折不扣的 - 但未来听起来更简单一些。 – Chris

1

您可以使用Future得到计数,并在末尾添加了所有的罪名,或者使用一个静态变量,并在​​方式增加它即使用明确地​​或者如果你的Runnable使用Atomic Increment

+0

非常感谢。 – Chris

+0

变量不一定是静态的,只需要就所有Runnables达成一致。 – yshavit

+0

@Chris:检查答案在这里http://stackoverflow.com/questions/8438497/multithreading-counting-total-amount-of-words-from-several-files/8438541#8438541 – Cratylus

1

花了两个参数:

  • 一个BlockingQueue<String>BlockingQueue<File>输入文件的
  • 的AtomicLong的

在一个循环中,您将从队列中获取下一个字符串/文件,计算其字数,并按该数量增加AtomicLong。循环是while(!queue.isEmpty())还是while(!done)取决于将文件送入队列的方式:如果您从头开始知道所有文件,则可以使用isEmpty版本,但是如果要从某个位置对其进行流式处理,则需要使用!done版本(并且donevolatile booleanAtomicBoolean用于内存可见性)。

然后你把这些Runnable送到执行者那里,你应该很好走。

+0

当我运行程序时,我将所有文件作为参数,所以我从一开始就知道它们。 并感谢你:) – Chris

1

你可以使countvolatilestatic所以所有的线程可以增加它。

public class WordCount implements Runnable 
{ 
    private static AtomicInteger count = new AtomicInteger(0); // <-- now all threads increment the same count 

    private String filename; 

    public WordCount(String filename) 
    { 
     this.filename = filename; 
    } 

    public static int getCount() 
    { 
     return count.get(); 
    } 

    public void run() 
    { 
     try 
     { 
     Scanner in = new Scanner(new File(filename)); 

     while (in.hasNext()) 
     { 
      in.next(); 
      count.incrementAndGet(); 
     } 
     System.out.println(filename + ": " + count); 
     } 
     catch (FileNotFoundException e) 
     { 
     System.out.println(filename + " blev ikke fundet."); 
     } 
    } 
} 

更新:有没有做过的java一段时间,但关于使其成为点私有静态字段仍然站立...只是使它成为AtomicInteger

+0

你最好使用AtomicInteger,post/pre-increment不是原子的 –

+0

'count ++'有一个竞争条件那里(看我对@ zmbq的回答的评论) – yshavit

+0

好点而在C#世界中),所以使用Atomic整数并将其设置为私有静态字段。 – Kiril

0

或者您可以让所有线程更新单个字数变量。如果计数是单词的话,count ++是原子的(一个int应该足够了)。

编辑︰原来的Java规格只是愚蠢的计数++是不是原子。我不知道为什么。无论如何,看看AtomicInteger及其incrementAndGet方法。希望这原子(我不知道现在期待什么......),并且您不需要任何其他同步机制 - 只需将您的计数存储在AtomicInteger中。

+0

'count ++'不是*原子的,即使它的字大小。你可以很容易地得到这样的东西:thread1读取count = 1,thread2读取count = 1,thread1递增1到2,thread2递增1到2,thread1写入count = 2,thread2写入count = 2。您必须使用同步或CAS(由AtomicLong或AtomicInteger提供)。 – yshavit

+0

抖动是不是计数++原子?如果抖动编译为INC [count]以外的任何值,则应该停用。 – zmbq

+0

只有32位或更少数量的读写才能保证为原子。增量不是原子操作 – Cratylus

1

您可以创建一些侦听器来从线程获取反馈。

public interface ResultListener { 
     public synchronized void result(int words); 
    } 
    private String filename; 
    private ResultListener listener; 
    public void run() 
    { 
    int count = 0; 
    try 
    { 
     Scanner in = new Scanner(new File(filename)); 

     while (in.hasNext()) 
     { 
      in.next(); 
      count++; 
     } 
     listener.result(count); 
    } 
    catch (FileNotFoundException e) 
    { 
     System.out.println(filename + " blev ikke fundet."); 
    } 
    } 
    } 

您可以像为您的文件名一样为侦听器添加一个构造器参数。

public class Main 
    { 
    private static int totalCount = 0; 
    private static ResultListener listener = new ResultListener(){ 
     public synchronized void result(int words){ 
      totalCount += words; 
     } 
    } 
    public static void main(String args[]) 
    { 
     for (String filename : args) 
     { 
      Runnable tester = new WordCount(filename, listener); 

      Thread t = new Thread(tester); 
      t.start(); 
     } 
    } 
    } 
+0

我刚要问,如果我不知道文件数量,代码中该怎么办。但我看到你改变了这一点。谢谢! – Chris

3

工作线程:

class WordCount extends Thread 
{ 

    int count; 

    @Override 
    public void run() 
    { 
     count = 0; 
     /* Count the words... */ 
     ... 
     ++count; 
     ... 
    } 

} 

和A类使用它们:

class Main 
{ 

    public static void main(String args[]) throws InterruptedException 
    { 
     WordCount[] counters = new WordCount[args.length]; 
     for (int idx = 0; idx < args.length; ++idx) { 
     counters[idx] = new WordCount(args[idx]); 
     counters[idx].start(); 
     } 
     int total = 0; 
     for (WordCount counter : counters) { 
     counter.join(); 
     total += counter.count; 
     } 
     System.out.println("Total: " + total); 
    } 

} 

许多硬盘驱动器不这样做的同时读取多个文件的非常出色。参考地点对性能有很大影响。

+0

非常有用。非常非常感谢你。 – Chris

+0

完美地工作。 – Chris