多线程处理-计算多个文件中的单词总数

问题描述 投票:4回答:7

我制作了一个程序来计算单个文件中的单词,但是我该如何修改我的程序,因此它给出了所有文件中的单词总数(作为一个值)。

我的代码如下:

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();
      }
   }
}

以及如何避免比赛条件?谢谢您的帮助。

java multithreading words
7个回答
3
投票

工作线程:

class WordCount extends Thread
{

   int count;

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

}

以及使用它们的类:

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);
   }

}

许多硬盘驱动器不能很好地同时读取多个文件。引用的位置对性能有很大影响。


1
投票

[您既可以使用Future获取计数,最后累加所有计数,也可以使用静态变量并以synchronized方式对其进行递增,即明确使用synchronized或使用Atomic Increment


1
投票

如果您的Runnable接受两个参数怎么办:

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

在循环中,您将从队列中获取下一个字符串/文件,计算其字数,然后将AtomicLong增加该数量。循环是while(!queue.isEmpty())还是while(!done)取决于将文件送入队列的方式:如果从一开始就知道所有文件,则可以使用isEmpty版本,但是如果要从某个位置将其流式传输,您想使用!done版本(并让done成为volatile booleanAtomicBoolean以提高内存可见性)。

然后您将这些Runnable馈给执行者,您应该会很好。


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();
        }
     }
  }

1
投票

您可以制作count volatilestatic,以便所有线程都可以递增它。

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
投票

您可以创建一个带有同步任务队列的线程池,该任务池将保存您要为其计算单词的所有文件。

当线程池工作者在线时,他们可以向任务队列请求要计数的文件。工人完成工作后,他们可以将其最终号码通知主线程。

主线程将具有一个同步的notify方法,它将所有工作线程的结果加起来。

希望这会有所帮助。


0
投票

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

编辑:事实证明Java规范足够愚蠢,以至于count ++是not原子的。我不知道为什么。无论如何,请看一下AtomicInteger及其递增AndGet方法。希望这个is原子(我现在不知道要期待什么...),并且您不需要任何其他同步机制-只需将您的计数存储在AtomicInteger中即可。


0
投票

我如何从此代码读取多个文件,我可以在其中放置要读取的实际文件名?我应该把第二个文件名放在哪里?

© www.soinside.com 2019 - 2024. All rights reserved.