关于Executors.newSingleThreadExecutor()的问题 [英] Question about the Executors.newSingleThreadExecutor()

查看:211
本文介绍了关于Executors.newSingleThreadExecutor()的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是有关以下代码的程序流程的问题:

  import java.util.concurrent.ExecutorService;导入java.util.concurrent.Executors;公开课测试{公共静态void main(String args []){ExecutorService服务= null;尝试 {服务= Executors.newSingleThreadExecutor();System.out.println("begin");service.execute(()-> System.out.println(打印动物园库存")));service.execute(()-> {for(int i = 0; i< 3; i ++)System.out.println(打印记录:" + i);});service.execute(()-> System.out.println(打印动物园库存")));} 最后 {if(服务!= null)service.shutdown();}}} 

在上面的代码中,一旦我们与"System.out.println("begin")交叉,...线程执行器便接连执行每个后续动作任务(基本上是Runnable lambda)./p>

我的理解是,这些任务"不一而足.(s.o.p("printing ..."),for-loop,s.o.p("printing."))将考虑到线程执行器"service",一个接一个地运行.在线程执行器上执行每个Runnable lambda.

我是否纠正了问题,除非Runnable lambda在当前行完成,否则程序流将不会移至下一行?例如,除非Runnable lambda完成s.o.p(打印动物园库存")...否则,它将不会在下一行开始下一个Runnable lambda吗?

如果当前线程执行器行带有计算密集型的Runnable lambda,那么在什么情况下会发生什么情况?在这种情况下,下一行(如果它包含另一个Runnable lambda)..是否必须等到当前线程执行程序完成任务?

解决方案

Q&一个

-是不是要纠正程序行将不会移至下一行,除非无法在当前行上完成的lambda吗?例如,除非Runnable lambda完成s.o.p(打印动物园库存"),否则它将不会在下一行开始下一个Runnable lambda吗?"

-是的,您是正确的. *

-" 如果当前线程执行程序行带有计算密集型的Runnable lambda,那么在什么情况下会发生什么情况?在这种情况下,下一行(如果它包含另一个Runnable lambda)..将不得不等到当前线程执行者完成任务?"

-是的,它必须等待. *

-""您喜欢的颜色?"

- 红色 .

(*)假设您要检查 ExecutorService 中的行为,将等式中的主线程(及其执行执行某些操作的调用)排除在等式之外,然后重点关注池中的内容工人线程.主线程是自己运行的,如果某些实现决定,某些实现也可能会为其分配任务,这就是本注释的原因..



Test&比较

我将尝试将此执行器与多线程执行器进行比较,以显示两种方法之间的差异.

关于您的问题(关注阻塞等待的情况),给出的答案会根据使用的执行程序服务而完全不同.使用第二个选项,答案将是:

  • 如果有工作人员,即使当前行没有结束,它也可以移动到下一行.

  • 不,如果有可用线程,则不必等待.

  • 红色.

SingleThreadExecutor

创建一个执行器,该执行器

在第三项任务上的突破-已经完成了两项


创建一个重用

John可以在线程2执行1的同时执行7个动作.对John来说更好的是,他能够在线程2完成分配的任务之前完成所有动作.约翰现在很安全,由于队列为空,它将完成任务并进入空闲状态.对约翰有好处.

  • thread-2 分配了 任务2 .但这一次睡眠不会导致工作队列增加,因为另一个线程能够同时执行它们.
  • thread-1 执行所有 4个重要任务: 5、6、7和8 .还为它分配了其他4个低优先级任务,能够在另一个线程繁忙"时清空工作队列.(睡觉).

This is a question regarding program flow of the following code:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
    public static void main(String args[]) {
        ExecutorService service = null;
        try {
            service = Executors.newSingleThreadExecutor();
            
            System.out.println("begin");
            service.execute(() -> System.out.println("Printing zoo inventory"));
            service.execute(() -> {
                for(int i = 0; i< 3; i++)
                    System.out.println("Printing record: " + i);
            });
            service.execute(() -> System.out.println("printing zoo inventory"));
        } finally {
            if(service != null)
                service.shutdown();
        }
    }
}

In the code above, once we cross the line with "System.out.println("begin")...the thread executor does each following action task (basically a Runnable lambda) one after the other.

My understanding is that these "tasks" (the s.o.p("printing..."), for-loop, s.o.p("printing..")) are going to be run one after the other considering the thread executor "service" executes each Runnable lambda on the thread executor.

Am i correct that the program flow will not move to the next line unless the Runnable lambda is finished on current line? For example, unless the Runnable lambda finishes for s.o.p("printing zoo inventory")...it wont start the next Runnable lambda on next line?

What happens in situation if the current thread executor line with a Runnable lambda that is computationally intensive? In this case, the next line (if it contains another Runnable lambda)..would have to wait until the current thread executor finishes the task?

解决方案

Q & A

-"Am i correct that the program flow will not move to the next line unless the unnable lambda is finished on current line? For example, unless the Runnable lambda finishes for s.o.p("printing zoo inventory")...it wont start the next Runnable lambda on next line?"

- Yes, you are correct.*

-"What happens in situation if the current thread executor line with a Runnable lambda that is computationally intensive? In this case, the next line (if it contains another Runnable lambda)..would have to wait until the current thread executor finishes the task?"

- Yes, it would have to wait.*

-"Your favorite color?"

-Red.

( * ) Assuming you are checking the behaviour from the ExecutorService, leaving out of the equation the main thread (and its invocation in order to execute something), and focusing on the pooled worker threads. The main thread runs by its own, and some implementations may also assign tasks to it if they decide to, that's why this note.



Test & Compare

I will try to compare this executor with a multithreaded one, in order to show the differences between both approaches.

Regarding your questions, which focus on the blocking-waiting scenario, the answers given differ completely based on the used executor service. Using the second option, the answers would be:

  • It will be able to move to the next line if a worker is avaliable, even if current line didn't finish.

  • No, it won't have to wait if a thread is avaliable.

  • Red.

SingleThreadExecutor

Creates an Executor that uses a single worker thread operating off an unbounded queue. Tasks are guaranteed to execute sequentially, and no more than one task will be active at any given time.

You only have a single thread on the pool, so all the tasks are assigned to it. It will have to sequentially execute them all, as stated on the docs. To make a simple test, for example:

service = Executors.newSingleThreadExecutor();
        
service.execute(() -> System.out.println("Printing zoo inventory"));
service.execute(() -> {
                        try {Thread.sleep(5000);    System.out.println("Woke up"); }
                        catch (InterruptedException e) {e.printStackTrace();}
                      });
service.execute(() -> System.out.println("Finish"));

Output

  Printing zoo inventory     // ---- [Thread 1] 
  //...5s 
  Woke up                    // ---- [Thread 1]
  Finish                     // ---- [Thread 1] -{x}- 

As shown in this at least mediocre time graph:

   {task1}    {task2}                          {task3}
      ^          ^                                ^
      |          |                     (~5s)      |
  [Thread1]-->[Thread1]---------------------->[Thread1]->{x}   

Debugging it, the only avaliable thread affirmes it was the one that executed the previous two tasks. The image examples are from original OP's question:

Breakpoint at third task - already two completed


MultiThreaded Pool

Using the FixedThreadPool for the example. The behaviour of the process changes when more than one worker thread is avaliable; For this example, two threads are set.

As always, the docs should be read carefully:

Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue. At any point, at most nThreads threads will be active processing tasks. If additional tasks are submitted when all threads are active, they will wait in the queue until a thread is available

Modified the test a little bit, to add some info regarding the working threads and perform some extra tasks.

volatile boolean wifeAlarm = false;
//...
service = Executors.newFixedThreadPool(2);

Once set, execute multiple tasks:

service.execute(() -> System.out.println("Woke up fast -" 
                      + Thread.currentThread().getName()));
service.execute(() -> 
{ 
  try {
         Thread.sleep(5000);    
         System.out.println("Woke up lazy - John where are you?? - {"+ 
                            Thread.currentThread().getName()+"}"); 
      } catch (InterruptedException e){}
       finally { wifeAlarm=true;}
 });
 service.execute(() -> System.out.println("Cleaning - {"
                       + Thread.currentThread().getName()+"}"));
 service.execute(() -> System.out.println("Making breakfast - {"
                       +Thread.currentThread().getName()+"}"));
 service.execute(() -> System.out.println("Flirt with neighbour - {"
                       +Thread.currentThread().getName()+"}"));
 service.execute(() -> System.out.println("Got her number - {"
                       +Thread.currentThread().getName()+"}"));
 service.execute(() -> System.out.println("Send hot af pic - {"
                       +Thread.currentThread().getName()+"}"));
 service.execute(() -> System.out.println("Remove all proof on phone - {"
                       +Thread.currentThread().getName()+"}"));
 service.execute(() -> 
 {
   try {
         while (!wifeAlarm)
             Thread.sleep(13);
         System.out.println("Just working my love - {"+ 
                            Thread.currentThread().getName()+"}"); 
       } catch (InterruptedException e) {}
  });

Output

Woke up fast - {pool-1-thread-1}
Cleaning - {pool-1-thread-1}
Making breakfast - {pool-1-thread-1}
Flirt with neighbour - {pool-1-thread-1}
Got her number - {pool-1-thread-1}
Send hot af pic - {pool-1-thread-1}
Remove all proof on phone - {pool-1-thread-1}
// ~4-5s
Woke up lazy - John where are you?? - {pool-1-thread-2}
Just working my love - {pool-1-thread-1}

This is just another terrible representation:

   {task1} {task2}  {task3}  (..)  {task9}
      ^       ^        ^              ^                     (~5s)
      |   [Thread2]--- | -------------|---------(...)----------->{x}        
  [Thread1] ----->[Thread1]--(..)-[Thread1]----------------------->{x}   
              

In resume: John has taken advantage of this new context, achieving something great thanks to the multithreaded pool.

John is able to execute 7 actions while thread-2 executes 1. Even better for John, he's able to finish them all before thread-2 finished its assigned task. John is safe now, it will finish its task and go IDLE, as the queue is empty. Good for John.

  • thread-2 is assigned task 2. But this time the sleep won't lead to an increase on the work queue, as the other thread is able to concurrently execute them.
  • thread-1 executes all the 4 vital tasks: 5, 6, 7 and 8. It is also assigned the other 4 low priority tasks, being able to empty the work queue while the other thread was "busy" (sleeping).

这篇关于关于Executors.newSingleThreadExecutor()的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆