繁体   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