2013-02-19 40 views
2

我是begginer,并保持自己的倾向。如何组织多线程与队列一起工作?

我需要做的组织multithreadings在文件中查找:

用户输入那里找到(路径),并在查找内容(字);

  • 第一个线程在文件夹中找到.txt文件并将结果添加到队列中;
  • 当队列中有一些文件=>第二个线程开始在这个文件中查找 需要查找什么(字)。
  • 如果被发现成功将显示路径这个文件+这个词在文件中遇到多少次。

Qestions:

  • 我们可以使用ArrayList(或存在任何替代)队列与线程数的作品?
  • 如果队列为空,第二个线程不启动,但在第一次发现需要文件时等待?
  • 需要我们使用同步这个任务,并继承MultiThreadingSearch(或更好地使用组合)?

代码:

import java.util.*; 
import java.io.*; 

class ArrayListOfFiles { 
    private Node first, last; 

    private class Node { 
     String item; 
     Node next; 
    } 

    public boolean isEmpty() { 
     return first == null; 
    } 

    public synchronized void enqueue(String item) { 
     Node oldlast = last; 
     last = new Node(); 
     last.item = item; 
     last.next = null; 
     if (isEmpty()) 
      first = last; 
     else 
      oldlast.next = last; 
    } 

    public synchronized String dequeue() { 
     String item = first.item; 
     first = first.next; 
     if (isEmpty()) 
      last = null; 
     return item; 
    } 
} 

class FolderScan extends MultiThreadingSearch implements Runnable { 

    FolderScan(String path, String whatFind) { 
     super(path, whatFind); 
    } 

    @Override 
    public void run() { 
     findFiles(path); 
    } 

    ArrayListOfFiles findFiles(String path) { 
     File root = new File(path); 
     File[] list = root.listFiles(); 
     for (File titleName : list) { 
      if (titleName.isDirectory()) { 
       findFiles(titleName.getAbsolutePath()); 
      } else { 
       if (titleName.getName().toLowerCase().endsWith((".txt"))) { 
        textFiles.enqueue(titleName.getName()); 
       } 
      } 
     } 

     return textFiles; 
    } 

} 

class FileScan extends MultiThreadingSearch implements Runnable { 
    Scanner scanner = new Scanner((Readable) textFiles); 
    Set<String> words = new HashSet<String>(); 
    int matches = 0; 

    FileScan(String file, String whatFind) { 
     super(file, whatFind); 
     Thread wordFind = new Thread(); 
     wordFind.start(); 
    } 

    @Override 
    public void run() { 
     while (scanner.hasNext()) { 
      String word = scanner.next(); 
      words.add(word); 
     } 

     if (words.contains(this.whatFind)) { 
      System.out.println("File:" + this.path); 
      matches++; 
     } 

     System.out.println(matches); 
    } 

} 

public class MultiThreadingSearch { 
    String path; 
    String whatFind; 

    ArrayListOfFiles textFiles; 

    MultiThreadingSearch(String path, String whatFind) { 
     this.path = path; 
     this.whatFind = whatFind; 
     this.textFiles = new ArrayListOfFiles(); 

     Thread pathFind = new Thread(new FolderScan(path, whatFind)); 
//  pathFind.start(); 

     if (!textFiles.isEmpty()) { 
      @SuppressWarnings("unused") 
      FileScan fileScan = new FileScan(textFiles.dequeue(), whatFind); 
     } 

    } 

    // ask user about input 
    public static void askUserPathAndWord() { 

     BufferedReader bufferedReader = new BufferedReader(
       new InputStreamReader(System.in)); 
     String path; 
     String whatFind; 
     try { 
      System.out.println("Please, enter a Path and Word" 
        + "(which you want to find):"); 
      System.out.println("Please enter a Path:"); 
      path = bufferedReader.readLine(); 
      System.out.println("Please enter a Word:"); 
      whatFind = bufferedReader.readLine(); 

      if (path != null && whatFind != null) { 
       new MultiThreadingSearch(path, whatFind); 
       System.out.println("Thank you!"); 
      } else { 
       System.out.println("You did not enter anything"); 
      } 

     } catch (IOException | RuntimeException e) { 
      System.out.println("Wrong input!"); 
      e.printStackTrace(); 
     } 
    } 


    public static void main(String[] args) { 
     askUserPathAndWord(); 
    } 
} 

我从这个代码得到Exception in thread "main" java.lang.StackOverflowError
如何能够解决这个任务?

谢谢,
Nazar。

+0

哪里(在哪一行)没有异常发生的? – rtheunissen 2013-02-19 10:55:41

+0

我怀疑在您发布的代码中未包含的某行上发生了异常。我在这里看不到任何会导致StackOverflowError – NickJ 2013-02-19 10:58:31

+1

线程中的异常“主”java.lang.StackOverflowError \t at task.MultiThreadingSearch。 (MultiThreadingSearch.java:101) \t at task.FolderScan。 (MultiThreadingSearch.java:41)' - 我没想到这回合 – 2013-02-19 11:05:41

回答

5

检查BlockingQueue它完全符合您的需求。线程可以阻塞,直到某个其他线程将新项目添加到队列中。
至于如何分解你的系统。我会做以下事情:

  • 创建类用于搜索路径中的txt文件。它实现Runnable。您将pathqueue传递给它。它搜索txt文件的路径并将它们添加到queu中。
  • 创建用于搜索文件内容的类。它实现Runnable。您将whatFindqueue传递给它,并从队列中获取新文件并检查其内容。

喜欢的东西:

BlockingQueue<File> queue = new LinkedBlockingQueue<File>(); 
String path = ...; 
String whatFind = ...; 
FolderScan folderScan = new FolderScan(path, queue); 
FileScan fileScan = new FileScan(whatFind, queue); 

Executor executor = Executors.newCachecThreadPool(); 
executor.execute(folderScan); 
executor.execute(fileScan); 

如果你想FileScan等到FolderScan增加了一些队列,你可以使用take方法:

BlockingQueue<File> queue; 
File toProcess = queue.take(); // this line blocks current thread (FileScan) until someone adds new item to the queue. 
+1

另一个问题呢?他们是重要的... – 2013-02-19 11:00:35

+1

你可以显示实现代码, – 2013-02-19 11:01:44

+1

'如果如果队列为空,第二个线程不启动,但等待时首先发现需要文件?' - 一般我不知道这应该怎么做。 .. – 2013-02-19 11:08:34

-1

这听起来可能不是太有建设性的,但您可以先修复该代码或先阅读this之类的代码,然后丢弃代码。 Stackoverflow通常由比预期运行更深的递归导致。确保递归方法中存在一些停止递归的条件。

+0

好吧,因为这是获得投票的方向:我的意思是,通常,当人们知道java.util.concurrent提供的抽象并且可能已经看到一些示例代码时,就会相应地设计自己的代码以利用该建筑物JDK中的块。而这当然需要扔掉自己的代码,试图重新发明轮子。 – 2013-02-19 13:15:47

0

变化后:

package task; 

import java.util.concurrent.*; 
import java.util.*; 
import java.io.*; 

class FolderScan implements Runnable { 

    private String path; 
    private BlockingQueue<File> queue; 
    private CountDownLatch latch; 
    private File endOfWorkFile; 

    FolderScan(String path, BlockingQueue<File> queue, CountDownLatch latch, 
      File endOfWorkFile) { 
     this.path = path; 
     this.queue = queue; 
     this.latch = latch; 
     this.endOfWorkFile = endOfWorkFile; 
    } 

    public FolderScan() { } 

    @Override 
    public void run() { 
     findFiles(path); 
     queue.add(endOfWorkFile); 
     latch.countDown(); 
    } 

    private void findFiles(String path) { 

     try { 
      File root = new File(path); 
      File[] list = root.listFiles(); 
      for (File currentFile : list) { 
       if (currentFile.isDirectory()) { 
        findFiles(currentFile.getAbsolutePath()); 
       } else { 
        if (currentFile.getName().toLowerCase().endsWith((".txt"))) { 
          queue.put(currentFile); 
        } 
       } 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

    } 

} 

public class FileScan implements Runnable { 

    private String whatFind; 
    private BlockingQueue<File> queue; 
    private CountDownLatch latch; 
    private File endOfWorkFile; 

    public FileScan(String whatFind, BlockingQueue<File> queue, 
      CountDownLatch latch, File endOfWorkFile) { 
     this.whatFind = whatFind; 
     this.queue = queue; 
     this.latch = latch; 
     this.endOfWorkFile = endOfWorkFile; 
    } 

    public FileScan() {  } 

    Set<String> words = new HashSet<String>(); 
    int matches = 0; 

    @Override 
    public void run() { 

     while (true) { 
      try { 
       File file; 
       file = queue.take(); 

       if (file == endOfWorkFile) { 
        break; 
       } 

       scan(file); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

     latch.countDown(); 
    } 

    private void scan(File file) { 
     Scanner scanner = null; 
     try { 
      scanner = new Scanner(file); 
     } catch (FileNotFoundException e) { 
      System.out.println("FileNotFoundException."); 
      e.printStackTrace(); 
     } 
     while (scanner.hasNext()) { 
      String word = scanner.next(); 
      words.add(word); 
     } 

     if (words.contains(this.whatFind)) { 
      matches++; 
     } 

     String myStr = String.format("File: %s and the number of matches " 
       + "is = %d", file.getAbsolutePath(), matches); 
     System.out.println(myStr); 

     matches = 0; 
    } 

    // ask user about input 
    public void askUserPathAndWord() { 

     BufferedReader bufferedReader = new BufferedReader(
       new InputStreamReader(System.in)); 
     String path; 
     String whatFind; 
     BlockingQueue<File> queue = new LinkedBlockingQueue<File>(); 

     try { 
      System.out.println("Please, enter a Path and Word" 
        + "(which you want to find):"); 
      System.out.println("Please enter a Path:"); 
      path = bufferedReader.readLine(); 
      System.out.println("Please enter a Word:"); 
      whatFind = bufferedReader.readLine(); 

      if (path != null && whatFind != null) { 

       File endOfWorkFile = new File("GameOver.tmp"); 
       CountDownLatch latch = new CountDownLatch(2); 

       FolderScan folderScan = new FolderScan(path, queue, latch, 
         endOfWorkFile); 
       FileScan fileScan = new FileScan(whatFind, queue, latch, 
         endOfWorkFile); 

       Executor executor = Executors.newCachedThreadPool(); 
       executor.execute(folderScan); 
       executor.execute(fileScan); 

       latch.await(); 
       System.out.println("Thank you!"); 
      } else { 
       System.out.println("You did not enter anything"); 
      } 

     } catch (IOException | RuntimeException e) { 
      System.out.println("Wrong input!"); 
      e.printStackTrace(); 
     } catch (InterruptedException e) { 
      System.out.println("Interrupted."); 
      e.printStackTrace(); 
     } 
    } 

    /** 
    * @param args 
    */ 

    public static void main(String[] args) { 
     new FileScan().askUserPathAndWord(); 
    } 
}