java线程重用

我一直认为创build线程很昂贵。 我也知道你不能重新运行一个线程。

我在Executors类的文档中看到:创build一个线程池,根据需要创build新线程,但在可用时会重用之前构build的线程。

注意“重用”一词。

线程池如何“重用”线程?

我想我明白了什么是confuzzabling你,所以这里是我更长的答案:术语是有点误导(显然,或者你不会问这个问题,具体强调'重用'):

线程池如何“重用”线程?

发生了什么事是一个线程可以用来处理几个任务(通常作为Runnable传递,但是这取决于你的“执行者”框架:默认的执行者接受Runnable,但你可以编写你自己的“执行者”/线程池接受一个比Runnable更复杂的东西[比如说,一个CancellableRunnable])。

现在在默认的ExecutorService实现中,如果一个线程在被使用时以某种方式被终止,它将被自动replace为一个新的线程,但这不是他们正在讨论的“重用”。 在这种情况下没有“重用”。

所以确实,你不能在一个Java线程上调用start()两次, 但是你可以像执行器那样传递尽可能多的Runnable ,并且每个Runnable的run()方法都应该被调用一次。

您可以将30个Runnable传递给5个Java Thread并且每个工作线程可能正在调用,例如run() 6次(实际上不能保证每个线程只能执行6个Runnable,但这是一个细节)。

在这个例子中,start()会被调用6次。 每个这6个start()都会调用一次每个Thread的run()方法:

从Thread.start()Javadoc:

  * Causes this thread to begin execution; the Java Virtual Machine * calls the <code>run</code> method of this thread. 

但是在每个线程的run()方法中, Runnable将被取出,并且每个Runnablerun()方法将被调用。 所以每个线程都可以处理好几个Runnable 。 这就是他们所说的“线程重用”。

一种做自己的线程池的方法是使用一个阻塞队列,在这个阻塞队列中可以将可运行队列排入队列中,并且一旦完成处理Runnablerun()方法,就让每个线程出列下一个Runnable (或block)并运行它的run()方法,然后冲洗并重复。

我猜部分困惑(这有点令人困惑)来自事实上,一个Thread需要一个Runnable并在调用start()时调用Runnable的run()方法,而默认的线程池采用Runnable

线程池中的线程的run方法不仅仅由运行单个任务组成。 线程池中线程的run方法包含一个循环。 它将任务从队列中取出,执行任务(完成时返回到循环 ),然后获取下一个任务。 run方法不会完成,直到线程不再需要。

编辑添加:

这是ThreadPoolExecutor中 Worker内部类的run方法。

 696: /** 697: * Main run loop 698: */ 699: public void run() { 700: try { 701: Runnable task = firstTask; 702: firstTask = null; 703: while (task != null || (task = getTask()) != null) { 704: runTask(task); 705: task = null; // unnecessary but can help GC 706: } 707: } finally { 708: workerDone(this); 709: } 710: } 

线程池由多个固定的工作线程组成,可以从内部任务队列中获取任务。 所以如果一个任务结束,线程不会结束,而是等待下一个任务。 如果放弃一个线程,它会自动replace。

查看文档以获取更多详细信息。

线程池创build自己的线程,并为这些线程提供自己聪明的小Runnable。 这些Runnables永远不会结束,而是在一个队列上同步(等待()),直到该队列中存在一个Callable。 当发生这种情况时会通知他们,而他们的Runnable从队列中运行Callable,并且整个场景再次重复。

如果thread完成,确保可以再次使用它。 你可以通过调用isAlive()或类似的东西来确定它没有运行。

编辑 :如果有人已经暂停一个thread ,一个不能再次启动。 如果正常结束,我不这样做。 但是我怀疑这个好处并且说它不能被重复使用。