簡體   English   中英

Java Multithreading使線程以與啟動時相同的順序結束,但同時運行

[英]Java Multithreading make threads end in same order they started but run at same time

我必須制作一個程序,從文件中搜索一堆行,然后嘗試找到給定的子字符串。 如果找到它,則打印出該行。 我讀取的每一行都創建為一個線程,並且每個線程都搜索文件的一行。 到目前為止,這不是問題。 我需要程序執行的操作是按照創建線程的順序打印最終結果(文本行)。 IE線程6不應在線程2之前進行打印。可以很好地確保線程同時運行,只需維護打印順序。 我不能使用join方法,因為我不希望下一個在開始之前完全等待另一個完成,我希望它們同時運行。 有什么建議嗎? 另外,該文件可以具有任意數量的行,因此我無法對線程數進行硬編碼。

螺紋應自行印刷。 主要不進行打印。

首先,很難定義線程應用程序的順序。 參見此處: 多線程中不需要的輸出

如果ExecutorService特定順序輸出,則可能應該使用ExecutorService ,它將返回Future 您將Callable<String>類提交給服務,每個類均返回結果。 提交返回Future<String> 然后,可以按照將作業提交給服務的順序從Future調用get()

// create a thread pool with 10 workers
ExecutorService threadPool = Executors.newFixedThreadPool(10);
// or you can create an open-ended thread pool
// ExecutorService threadPool = Executors.newCachedThreadPool();
// define your jobs somehow as a Callable that returns the line (prolly a string)
List<Future<String>> futures = threadPool.invokeAll(jobsToDo);
// once we have submitted all jobs to the thread pool, it should be shutdown
threadPool.shutdown();
// now we can go through the futures and get the results in order
for (Future<String> future : futures) {
    // this returns the results from the `call()` in order or it throws
    String resultFromCall = future.get();
}

您的工作Callable類看起來像:

public class MyCallable implements Callable<String> {
    private String input;
    public MyCallable(String input) {
        this.input = input;
    }
    public String call() {
        // search the input string
        String result = search(input);
        return result;
    }
}

實際上,您可以使用join() 但是您確實需要在適當的時間和地點調用它。 針對您的新要求進行了更新:“主線程不應打印結果,輔助線程應打印結果”。

注意:這種類型的程序實際上最好使用java.util.concurrent中的實用程序類編寫。 但是,我使用線程“基類”編寫了這個示例,以幫助學習。 請注意reggert的評論(上文)-在文件中每行文本盲目創建一個線程可能會導致太多線程,從而導致程序崩潰或操作系統不堪重負。 最好使用線程池(例如java.util.concurrent.Executors )完成這種工作委派。

public class MultiThreadedLineSearcher {

    public static void main(String[] args) throws Exception {
        Thread previousThread = null;
        for (int i = 0; i < LINES.length; i++) {
            JobRunnable job = new JobRunnable(i, LINES[i], previousThread);
            Thread thread = new Thread(job, "T-" + i);
            thread.start();
            previousThread = thread;
        }
        if (previousThread != null) {
            previousThread.join();
        }
        System.out.println("Program done.");
    }

    public static class JobRunnable implements Runnable {
        private final int _lineIdx;
        private final String _lineText;
        private final Thread _threadToWaitForBeforePrinting;

        public JobRunnable(int lineIdx, String lineText,
                Thread threadToWaitForBeforePrinting) {
            _lineIdx = lineIdx;
            _lineText = lineText;
            _threadToWaitForBeforePrinting = threadToWaitForBeforePrinting;
        }

        public void run() {
            try {
                boolean matched = FIND_ME.matcher(_lineText).find();
                String currentThreadName = Thread.currentThread().getName();
                System.out.println("Thread " + currentThreadName
                        + " is done with its work.");
                if (_threadToWaitForBeforePrinting != null) {
                    System.out.println("Thread " + currentThreadName
                            + " will wait for thread "
                            + _threadToWaitForBeforePrinting.getName()
                            + " before printing its results.");
                    _threadToWaitForBeforePrinting.join();
                }
                System.out.println("RESULT: " + _lineIdx + " matched? "
                        + matched + " (Printed on Thread "
                        + currentThreadName + ")");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    final static String[] LINES = new String[] {
        "Sed ut perspiciatis unde omnis iste natus error sit voluptatem",
        "accusantium doloremque laudantium, totam rem aperiam, eaque ipsa",
        "quae ab illo inventore veritatis et quasi architecto beatae vitae",
        "dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas",
        "sit aspernatur aut odit aut fugit, sed quia consequuntur magni",
        "dolores eos qui ratione voluptatem sequi nesciunt. Neque porro",
        "quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur,",
        "adipisci velit, sed quia non numquam eius modi tempora incidunt",
        "ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad",
        "minima veniam, quis nostrum exercitationem ullam corporis",
        "suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?",
        "Quis autem vel eum iure reprehenderit qui in ea voluptate velit",
        "esse quam nihil molestiae consequatur, vel illum qui dolorem eum",
        "fugiat quo voluptas nulla pariatur?" };

    // Match only words that are 11 characters or longer
    final static java.util.regex.Pattern FIND_ME = 
            java.util.regex.Pattern.compile("\\w{11,}");
}

這是執行程序可以執行的方法:

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class MultiThreadedLineSearcherExecutor {

    static final int MAX_THREADS = 10;

    public static void main(String[] args) throws Exception {
        // Create as many threads as there are lines of text,
        // but do not exceed 10 threads
        int lineCount = LINES.length;
        int threadPoolSize = Math.min(MAX_THREADS, lineCount);
        System.out.println("Number of lines = " + lineCount);
        System.out.println("Thread pool size = " + threadPoolSize);
        ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
        Future previousFuture = null;
        for (int i = 0; i < lineCount; i++) {
            JobRunnable job = new JobRunnable(i, LINES[i], previousFuture);
            previousFuture = executor.submit(job);
        }
        executor.shutdown();
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
        System.out.println("Program done.");
    }

    public static class JobRunnable implements Runnable {
        private final int _lineIdx;
        private final String _lineText;
        private final Future _futureToWaitForBeforePrinting;

        public JobRunnable(int lineIdx, String lineText,
                Future previousFuture) {
            _lineIdx = lineIdx;
            _lineText = lineText;
            _futureToWaitForBeforePrinting = previousFuture;
        }

        public void run() {
            try {
                boolean matched = FIND_ME.matcher(_lineText).find();
                String currentThreadName = Thread.currentThread().getName();
                System.out.println("Thread " + currentThreadName
                        + " is done with its work on line " + _lineIdx);
                if (_futureToWaitForBeforePrinting != null) {
                    System.out.println("Thread " + currentThreadName
                            + " will wait for future "
                            + _futureToWaitForBeforePrinting
                            + " before printing its results.");
                    _futureToWaitForBeforePrinting.get();
                }
                System.out.println("RESULT: " + _lineIdx + " matched? "
                        + matched + " (Printed on Thread "
                        + currentThreadName + ")");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

    final static String[] LINES = new String[] {
        "Sed ut perspiciatis unde omnis iste natus error sit voluptatem",
        "accusantium doloremque laudantium, totam rem aperiam, eaque ipsa",
        "quae ab illo inventore veritatis et quasi architecto beatae vitae",
        "dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas",
        "sit aspernatur aut odit aut fugit, sed quia consequuntur magni",
        "dolores eos qui ratione voluptatem sequi nesciunt. Neque porro",
        "quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur,",
        "adipisci velit, sed quia non numquam eius modi tempora incidunt",
        "ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad",
        "minima veniam, quis nostrum exercitationem ullam corporis",
        "suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?",
        "Quis autem vel eum iure reprehenderit qui in ea voluptate velit",
        "esse quam nihil molestiae consequatur, vel illum qui dolorem eum",
        "fugiat quo voluptas nulla pariatur?" };

    // Match only words that are 11 characters or longer
    final static java.util.regex.Pattern FIND_ME = 
            java.util.regex.Pattern.compile("\\w{11,}");
}

我不能使用join方法,因為我不希望下一個在開始之前完全等待另一個完成,我希望它們同時運行。

您可以使它們填充一個數組(其中每個元素“知道”要填充的元素,作為其初始狀態的一部分),然后加入所有線程,以便等待它們完成,然后僅打印按順序列出數組的內容。

我將使用某種集合來對結果進行排序。 每個線程將啟動一個具有計數器的Runnable 像這樣:

private Map<Integer, String> map = new HashMap<Integer, String>();
int counter = 1;
while (line = getNextLine()) {
    Runnable runnable = new PrinterRunnable(line, counter);
    ++counter;
}

Runnable看起來像:

public PrinterRunnable implements Runnable {

   private String line;
   private Integer counter;

   public PrinterRunnable(String line, Integer counter) {
       this.line = line;
       this.counter = counter;
   }


   public run () {
      // Do some work on line and keep in the map the result where counter is the key
   }
}

重要說明 :在此示例中, PrinterRunnable應該是運行代碼的類的內部類,以便它能夠訪問地圖(或者您應該以其他方式傳遞對地圖的引用)。

最后,您可以對地圖的keySet()進行排序,然后相應地打印值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM