为什么我的线程不能同时启动? Java的

时间:2010-12-27 19:35:02

标签: java multithreading

我有可变数量的线程用于并行下载。我用过这个,

for(int i = 0; i< sth; i++){
       thrList.add(new myThread (parameters));
       thrList.get(i).start();
       thrList.get(i).join();

}

我不知道为什么,但他们等待彼此完成。当使用线程时,我应该得到混合打印输出,因为那时有几个线程运行该代码。但是,当我打印出来时,它们总是处于有序状态,并且一个线程等待前一个线程先完成。我只希望他们加入主线程,而不是等待对方。我注意到,当我在平行下载时测量时间。

我该如何解决这个问题?他们为什么要这样做呢?

在我的.java中, 有运行的MyThread类,还有带有静态方法和变量的Downloader类。他们会成为这个原因吗?静态方法和变量?

如何解决此问题?

7 个答案:

答案 0 :(得分:11)

您正在创建一个线程,等待它完成(加入),创建一个新线程,等待它完成(加入)等。

你应该阅读有关线程的java文档,知道大多数方法的作用: http://download.oracle.com/javase/tutorial/essential/concurrency/index.htmlhttp://download.oracle.com/javase/6/docs/api/java/lang/Thread.html

答案 1 :(得分:2)

易。问题出在这里:

for(int i = 0; i< sth; i++){
       thrList.add(new myThread (parameters));
       thrList.get(i).start(); // problem
       thrList.get(i).join();  // problem
}

具体来说,循环的每次迭代都是创建一个线程,启动它然后等待它再次加入。这就是他们串行运行的原因。

您需要做的是:

for(int i = 0; i< sth; i++){
       thrList.add(new myThread (parameters));
       thrList.get(i).start();
}

for(int i = 0; i< sth; i++){
       thrList.get(i).join();
}

这将完成启动所有线程的过程,然后它将循环遍历每个线程并等待它退出。

答案 2 :(得分:1)

你启动一个线程并立即加入它,从而使整个线程无用,因为你正在等待线程的完成。

   thrList.get(i).start();
   thrList.get(i).join();

您应该使用一个同步队列,其中生成的线程自己从中获取参数,等待队列为空,然后继续。

答案 3 :(得分:1)

join方法等待所选线程死掉。当前线程(执行触发事件的循环的线程)正在等待刚开始死的线程,然后再次出现并开始下一个线程。

答案 4 :(得分:1)

使用ExecutorService

会好得多
ExecutorService es = Executors.newCachedThreadPool();
// pool is reusable

List<Callable<Void>> callables = new ArrayList<Callable<Void>>();
for(int i=0;i<sth;i++) callables.add(new MyCallable(i));
for(Future<Void> futures : es.invokeAll(callables))
    futures.get();

答案 5 :(得分:0)

只做2个循环,首先启动所有循环,然后将它们全部加入。

答案 6 :(得分:0)

对于我从您的问题中解释的内容,由于没有明确说明,您是否有多个下载程序线程并希望同步它们。在这种情况下,您需要使用外部结构,例如CountdownLatch。 CountdownLatch是一种“同步辅助工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。”可以把它想象成一个计数器,每当下载程序线程完成时减少,当倒计时达到0时,所有线程都应该完成它们的工作。

让我们看一下代码直接来自CountdownLatch的官方javadoc:

 CountDownLatch startSignal = new CountDownLatch(1);
 CountDownLatch doneSignal = new CountDownLatch(N);

 for (int i = 0; i < N; ++i) // create and start threads
     new Thread(new Worker(startSignal, doneSignal)).start(); 

 startSignal.countDown(); // Threads are waiting for startSignal's counter to reach 0 and start their work, more or less at the same time
 doneSignal.await(); // The current thread will sleep at this point until all worker threads have each one called doneSignal.countDown() and the countdown reaches 0

 joinDownloadedPieces(); // At this point is safe to assume that your threads have finished and you can go on with anything else    

你的工作者Runnable / Thread类看起来像这样:

public void run() {
    startSignal.await(); // Wait until given the go

    downloadSomething();

    doneSignal.countDown(); // Notify that we are done here
}

我说可以安全地假设,因为您必须处理InterruptedExceptions,它们可以在等待之前唤醒您的线程,然后才能完成。有关详细信息,我建议您查看java.util.concurrent包。它是恕我直言最好的Java之一,文档是彻底的,通常足以理解每个结构的功能。