>我下面有一个示例 java 代码,如果作为控制台应用程序运行,则其行为符合我的预期(生成单个线程以执行可运行的线程(。
我看到的奇怪行为(生成两个线程 - 下面的示例(是当我使用 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的测试器。行为是相同的。
更新2 输出:
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
唯一合理的结论是,您(或框架(正在创建两个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();
这与应用程序中发生的情况类似。
我实际上在我的电脑上尝试了这段代码,就像这样,
import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; 公共类执行器测试{ public void testIt(({ ExecutorService ex = Executors.newSingleThreadExecutor((; ex.execute(new Runnable(({ public void run(( { 而(真({ System.out.printf("Thread -" + Thread.currentThread((.getId(( + " Current time: %tr%n", new Date(((; 尝试{ 线程睡眠(1000(; }catch(InterruptedException ie({ ie.printStackTrace((; } } } }); } public static void main(String[] args( { ExecutorTest x = new ExecutorTest((; x.testIt((; } }
我只得到一个线程,
线程 -10 当前时间: 09:50:27 PM线程 -10 当前时间: 09:50:28 PM线程 -10 当前时间: 09:50:29 PM线程 -10 当前时间: 09:50:30 PM线程 -10 当前时间: 09:50:31 PM线程 -10 当前时间: 09:50:32 PM线程 -10 当前时间: 09:50:33 PM
所以大多数情况下,在你实例化类的方式上可能会出现错误