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

时间:2014-12-04 15:06:56

标签: java multithreading java-7 executorservice scheduledexecutorservice

我有一个示例java代码,如果作为控制台应用程序运行,则表现得像我预期的那样(产生一个线程来执行runnable)。

奇怪的行为(产生两个线程 - 下面的示例)我看到的是当我使用Apache的prunsrv64.exe将此示例作为服务应用程序运行时。

我正在Windows 7计算机上测试 - 64位。

示例输出:

   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

示例代码:

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();
                    }                   
                }

            }
        });     
    }
}

感谢。

更新: 只是为了澄清我正在调用此代码如下:

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

如上所述,当作为控制台应用程序和服务应用程序运行时,没有更改的相同代码的行为会有所不同。


更新2: 我添加了第二个使用ScheduledExecutorService的测试人员。行为是一样的。

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

更新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();

更新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

2 个答案:

答案 0 :(得分:4)

唯一合理的结论是你(或框架)正在创建ExecutorTest的两个引用并执行两次。

将对象的identityHashCode添加到日志记录中。

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

  

如上所述,当作为控制台应用程序和服务应用程序运行时,没有更改的相同代码的行为会有所不同。

您可以精确控制在此创建的数量。


修改根据您的第三次更新。

我的假设是正确的,对象的System.identityHashCode类似于其内存位置。如您所见,这两个值不同,但如果ExecutorService创建了两个线程,那么这些值将是相同的。

这意味着您正在创建多个实例。也许不是你直接,但框架正在创建多个相同的服务并运行它们。

因此,这从'为什么执行者服务创建2个线程'到'为什么我的框架创建两个服务实例'的问题。这个问题我无法回答。

为了更清楚地说明,想象一下像这样执行你的测试

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

这与您的应用程序中发生的情况类似。

答案 1 :(得分:1)

我实际上在我的电脑上尝试过这样的代码,


    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();
        }
    }

我只得到一个帖子,

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

因此大多数情况下,您实例化类

的方式可能会出错