简体   繁体   English

为什么java ExecutorService newSingleThreadExecutor产生两个线程?

[英]Why is java ExecutorService newSingleThreadExecutor spawning two threads?

I have a sample java code below which if run as a console application behaves as I expected ( spawning a single thread to execute the runnable). 我有一个示例Java代码,如果该代码作为控制台应用程序运行,则其行为符合我的预期(生成单个线程来执行可运行对象)。

The strange behavior (spawning two threads - sample below) I see is when I run this sample as a service application using Apache's prunsrv64.exe. 我看到的奇怪行为(产生两个线程-下面的示例)是当我使用Apache的prunsrv64.exe作为服务应用程序运行此示例时。

I am testing this on a Windows 7 machine - 64bit. 我正在Windows 7机器-64位上对此进行测试。

Sample Output: 样本输出:

   Thread -28 Current time: 09:50:11 AM
   Thread -52 Current time: 09:50:12 AM
   Thread -28 Current time: 09:50:21 AM
   Thread -52 Current time: 09:50:22 AM
   Thread -28 Current time: 09:50:31 AM
   Thread -52 Current time: 09:50:32 AM

Sample Code: 样例代码:

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

public class ExecutorTest{
    public void testIt(){
        ExecutorService ex = Executors.newSingleThreadExecutor();
        ex.execute(new Runnable(){
            public void run() {
                while(true){
                    System.out.printf("Thread -" + Thread.currentThread().getId() + " Current time: %tr%n", new Date());
                    try{
                        Thread.sleep(10000);    
                    }catch(InterruptedException ie){
                        ie.printStackTrace();
                    }                   
                }

            }
        });     
    }
}

Thanks. 谢谢。

Update: Just to clarify I am calling this code as follows: 更新:为了澄清一下,我将这段代码称为:

    ExecutorTest tester = new ExecutorTest();
    tester.testIt();

The same code without changes is behaving differently when run as console application and a service application as I mentioned above. 如前所述,作为控制台应用程序和服务应用程序运行时,没有更改的相同代码的行为会有所不同。


Update 2: I added a second tester which uses a ScheduledExecutorService. 更新2:我添加了第二个使用ScheduledExecutorService的测试器。 The behavior is the same. 行为是相同的。

Update2 Output: Update2输出:

Using ScheduledExecutorService.
Thread Id outside Runnable -1
Thread -53 Current time: 10:58:15 AM
Thread -28 Current time: 10:58:24 AM
Thread -53 Current time: 10:58:25 AM
Thread -28 Current time: 10:58:34 AM
Thread -53 Current time: 10:58:35 AM
Thread -28 Current time: 10:58:44 AM
Thread -53 Current time: 10:58:45 AM
Thread -28 Current time: 10:58:54 AM
Thread -53 Current time: 10:58:55 AM
Thread -28 Current time: 10:59:04 AM
Thread -53 Current time: 10:59:05 AM

Update 2 Code: 更新2代码:

public void testItWithScheduled(){
    System.out.println("Using ScheduledExecutorService.");
    ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
    System.out.println("Thread Id outside Runnable -" + Thread.currentThread().getId());
    ex.scheduleWithFixedDelay(new Runnable(){
        public void run() {
            System.out.printf("Thread -" + Thread.currentThread().getId() + " Current time: %tr%n", new Date());
        }
    },0L, 10, TimeUnit.SECONDS);        
}


called through:

    ExecutorTest tester = new ExecutorTest();
    tester.testItWithScheduled();

Update 3: Modified logging to add identity hash 更新3:修改日志记录以添加标识哈希

Using ScheduledExecutorService.
Thread Id outside Runnable 1 with reference: 1370756928
Thread -53 Current time: 11:10:38 AM with reference: 1370756928
Thread -28 Current time: 11:10:47 AM with reference: 1939972532
Thread -53 Current time: 11:10:48 AM with reference: 1370756928
Thread -28 Current time: 11:10:57 AM with reference: 1939972532
Thread -53 Current time: 11:10:58 AM with reference: 1370756928
Thread -28 Current time: 11:11:07 AM with reference: 1939972532
Thread -53 Current time: 11:11:08 AM with reference: 1370756928

The only reasonable conclusion is that you (or the framework) are creating two references of ExecutorTest and executing it twice. 唯一合理的结论是您(或框架)正在创建ExecutorTest两个引用并执行两次。

Add the identityHashCode of the object to your logging. 将对象的identityHashCode添加到您的日志记录中。

System.out.printf("Thread -" + Thread.currentThread().getId() + " Current time: %tr with reference: %s%n ", new Date(), System.identityHashCode(ExecutorTest.this));

The same code without changes is behaving differently when run as console application and a service application as I mentioned above. 如前所述,作为控制台应用程序和服务应用程序运行时,没有更改的相同代码的行为会有所不同。

You control exactly how many are being created here. 您可以精确控制此处要创建的数量。


Edit Based on your third update. 根据您的第三个更新进行编辑

My assumption is correct, the System.identityHashCode of an object is analogous to its memory location. 我的假设是正确的,对象的System.identityHashCode类似于其内存位置。 As you can see the two values are different but if the ExecutorService was creating two threads, those values would be the same. 如您所见,这两个值是不同的,但是如果ExecutorService正在创建两个线程,则这些值将是相同的。

That means you are creating multiple instances. 这意味着您正在创建多个实例。 Maybe not you directly, but the framework is creating multiple of the same service and running them. 也许不是您直接,而是该框架正在创建多个相同的服务并运行它们。

So this moves from a question of 'why is the executor service creating 2 threads' to 'why is my framework creating two service instances'. 因此,这从“为什么执行程序服务会创建两个线程”这一问题过渡到“为什么我的框架会创建两个服务实例”。 That question I cannot answer. 我无法回答这个问题。

To clarify more clearly, imagine executing your test like this 为了更清楚地说明,想象一下执行这样的测试

ExecutorTest tester1 = new ExecutorTest();
tester1.testIt();
ExecutorTest tester2 = new ExecutorTest();
tester2.testIt();

That is similar to what is occurring in your application. 这类似于您的应用程序中发生的情况。

I actually tried this code in my pc like this , 我实际上是在我的PC中尝试过这样的代码,

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

    public class ExecutorTest{
        public void testIt(){
            ExecutorService ex = Executors.newSingleThreadExecutor();
            ex.execute(new Runnable(){
                public void run() {
                    while(true){
                        System.out.printf("Thread -" + Thread.currentThread().getId() + " Current time: %tr%n", new Date());
                        try{
                            Thread.sleep(1000);    
                        }catch(InterruptedException ie){
                            ie.printStackTrace();
                        }                   
                    }

                }
            });     
        }
        public static void main(String[] args) {
            ExecutorTest x = new ExecutorTest();
            x.testIt();
        }
    }

and I m getting only one thread, 我只有一个线程,

Thread -10 Current time: 09:50:27 PM
Thread -10 Current time: 09:50:28 PM
Thread -10 Current time: 09:50:29 PM
Thread -10 Current time: 09:50:30 PM
Thread -10 Current time: 09:50:31 PM
Thread -10 Current time: 09:50:32 PM
Thread -10 Current time: 09:50:33 PM

so mostly there can be an error on the way you are instantiating the class 因此大多数情况下,您实例化类的方式可能会出错

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM