了解线程

时间:2016-05-08 11:00:16

标签: java multithreading

我编写了一个简单的程序,旨在启动一些线程。然后线程应该从整数数组中选择一个整数 n ,用它来等待 n 并返回线程等待的时间 t 结果数组。

如果一个线程完成了它的任务,它应该选择下一个尚未分配给另一个线程的线程。
当然:必须维护数组中的顺序,以便整数和结果匹配。

据我所知,我的代码运行顺畅。 但是我使用了一行特别不满意的代码块,并希望有一个很好的方法来解决这个问题,而不会改变太多:

while(Thread.activeCount() != 1); // first evil line

我有点滥用这一行,以确保在我使用结果访问我的数组之前,我的所有线程都完成了所有任务。我想这样做是为了防止错误的值,比如0.0,Null Pointer Exception ...等等(简而言之,任何会导致应用程序出现实际使用崩溃的东西) 任何形式的建设性帮助表示赞赏。我也不确定,如果我的代码仍能在线程的非常长的任务数组中顺利运行,例如结果不再与整数的顺序匹配。

任何建设性的帮助表示赞赏。

头等舱:

public class ThreadArrayWriterTest {

    int[] repitions;
    int len = 0;
    double[] timeConsumed;

    public boolean finished() {
        synchronized (repitions) {
            return len <= 0;
        }
    }

    public ThreadArrayWriterTest(int[] repitions) {
        this.repitions = repitions;
        this.len = repitions.length;
        timeConsumed = new double[this.len];
    }

    public double[] returnTimes(int[] repititions, int numOfThreads, TimeConsumer timeConsumer) {

        for (int i = 0; i < numOfThreads; i++) {
            new Thread() {
                public void run() {
                    while (!finished()) {
                        len--;
                        timeConsumed[len] = timeConsumer.returnTimeConsumed(repititions[len]);
                    }
                }

            }.start();
        }
        while (Thread.activeCount() != 1) // first evil line
            ;
        return timeConsumed;
    }

    public static void main(String[] args) {
        long begin = System.currentTimeMillis();
        int[] repitions = { 3, 1, 3, 1, 2, 1, 3, 3, 3 };
        int numberOfThreads = 10;

        ThreadArrayWriterTest t = new ThreadArrayWriterTest(repitions);
        double[] times = t.returnTimes(repitions, numberOfThreads, new TimeConsumer());
        for (double d : times) {
            System.out.println(d);
        }
        long end = System.currentTimeMillis();
        System.out.println("Total time of execution: " + (end - begin));
    }
}

第二课:

public class TimeConsumer {

    double returnTimeConsumed(int repitions) {
        long before = System.currentTimeMillis();
        for (int i = 0; i < repitions; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        long after = System.currentTimeMillis();
        double ret = after - before;
        System.out.println("It takes: " + ret + "ms" + " for " + repitions + " runs through the for-loop");
        return ret;
    }
}

3 个答案:

答案 0 :(得分:1)

等待所有线程完成的最简单方法是保留它们的集合,然后依次为每个线程调用Thread.join()

答案 1 :(得分:1)

除了.join(),您还可以使用ExecutorService来管理线程池,

  

Executor,提供管理终止和方法的方法   这可以产生一个跟踪一个或多个进度的Future   异步任务。

     

可以关闭ExecutorService,这将导致它拒绝新的   任务。提供了两种不同的方法来关闭   ExecutorService的。 shutdown()方法将允许先前提交   在终止之前执行的任务,而shutdownNow()方法   阻止等待任务启动并尝试暂停   执行任务。终止后,执行者没有主动执行任务   执行,没有等待执行的任务,也没有新的任务   提交。应该关闭一个未使用的ExecutorService以允许   回收其资源。

     

方法提交扩展基本方法Executor.execute(Runnable)   创建并返回可用于取消执行的Future   和/或等待完成。方法invokeAny和invokeAll执行   最常用的批量执行形式,执行a   收集任务,然后等待至少一个或全部   完整。

ExecutorService executorService = Executors.newFixedThreadPool(maximumNumberOfThreads);
CompletionService completionService = new ExecutorCompletionService(executorService);
for (int i = 0; i < numberOfTasks; ++i) {
     completionService.take(); 
}
executorService.shutdown();

另外,请查看ThreadPoolExecutor

答案 2 :(得分:0)

由于java提供了带有concurrent包的更高级的线程API,您应该查看ExecutorService,这简化了线程管理机制。

简单解决您的问题。

  1. 使用Executors API创建线程池

    static ExecutorService  newFixedThreadPool(int nThreads)
    
      

    创建一个线程池,该线程池重用在共享的无界队列中运行的固定数量的线程。

  2. 使用invokeAll等待所有任务完成。

    示例代码:

    ExecutorService service = Executors.newFixedThreadPool(10);
    
    List<MyCallable> futureList = new ArrayList<MyCallable>();
    for ( int i=0; i<12; i++){
        MyCallable myCallable = new MyCallable((long)i);
        futureList.add(myCallable);
    }
    System.out.println("Start");
    try{
        List<Future<Long>> futures = service.invokeAll(futureList);  
        for(Future<Long> future : futures){
            try{
                System.out.println("future.isDone = " + future.isDone());
                System.out.println("future: call ="+future.get());
            }
            catch(Exception err1){
                err1.printStackTrace();
            }
        }
    }catch(Exception err){
        err.printStackTrace();
    }
    service.shutdown();
    
  3. 有关实现相同的更多详细信息,请参阅此相关的SE问题:

    wait until all threads finish their work in java