java线程重用

Bob*_*Bob 54 java multithreading

我一直认为创建线程很昂贵.
我也知道你不能重新运行一个帖子.

我在Executors课堂上看到:

创建一个根据需要创建新线程的线程池,但在它们可用时将重用先前构造的线程.

注意'重用'这个词.

线程池如何"重用"线程?

Syn*_*r0r 50

我想我明白了什么让你感到困惑所以这里是我的答案:这个术语有点误导(显然,或者你不会特别强调'重用'这个问题):

线程池如何"重用"线程?

发生的事情是单个线程可用于处理多个任务(通常作为传递Runnable,但这取决于您的'执行者'框架:默认执行程序接受Runnable,但您可以编写自己的"执行程序"/线程池接受某些内容比Runnable[比如说,a CancellableRunnable] 更复杂.

现在在默认ExecutorService实现中,如果某个线程在仍在使用时以某种方式终止,它将自动替换为新线程,但这不是他们所讨论的"重用".在这种情况下没有"重用".

因此,它是真实的,你不能说start()在一个Java线程的两倍,但你可以通过尽可能多的Runnable,只要你想执行人和各Runnablerun()方法将被调用一次.

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

在这个例子start()中将被调用6次.每个人这6 start()将调用仅一次run()每个方法Thread:

来自Thread.start()Javadoc:

 * Causes this thread to begin execution; the Java Virtual Machine 
 * calls the <code>run</code> method of this thread.
Run Code Online (Sandbox Code Playgroud)

随后每个线程的内部run()方法Runnable必须离队,并在run()每一个方法Runnable将被调用.所以每个线程都可以处理几个Runnable.这就是他们通过"线程重用"所指的内容.

执行自己的线程池的一种方法是使用一个阻塞队列,在该队列中将runnables排入队列并拥有每个线程,一旦处理完run()a 的方法Runnable,将下一个Runnable(或块)出列并运行其run()方法,然后冲洗并重复.

我猜混乱的一部分(这是一个有点混乱)来自于一个事实,即Thread需要Runnable和在调用start()Runnable的run()方法被调用,而默认的线程池需要Runnable.

  • tl; dr线程池线程基本上是运行循环,将提交的任务从队列中拉出.线程在为任务提供服务时不会停止执行,只是等待下一个线程提交到队列.他们永远不会像问题中那样"重新运行",因为他们只是在不停地跑步. (30认同)
  • 这里解释了上述实现的一个例子(http://tutorials.jenkov.com/java-concurrency/thread-pools.html) (2认同)

Mik*_*els 14

run线程的线程池的方法并不只包括运行单个任务.run线程池中线程的方法包含一个循环.它将任务从队列中拉出,执行任务(在完成时返回循环),然后获取下一个任务.在run不再需要该线程之前,该方法不会完成.

编辑添加:

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

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:         }
Run Code Online (Sandbox Code Playgroud)

  • @Wizard:实际上并不是必要的 - 循环中的(奇怪的)任务测试!= null使得必须防止不断处理相同的任务.即使循环更常规,归零任务也会很好,否则如果getTask()长时间阻塞,则任务的GC将被延迟相同的时间长度. (5认同)

And*_*Dog 5

线程池由许多固定工作线程组成,这些线程可以从内部任务队列中接收任务。所以,如果一个任务结束时,线程并没有结束,但下个任务等待。如果中止线程,该线程将被自动替换。

请参阅文档以获取更多详细信息。