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).
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.
I am testing this on a Windows 7 machine - 64bit.
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. The behavior is the same.
Update2 Output:
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:
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
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
In the specific case of an ExecutorService , I would vote for supporting thread interruption rather than a flag. In many frameworks, the service will be terminated with shutdownNow() .
ExecutorService is a JDK API that simplifies running tasks in asynchronous mode. Generally speaking, ExecutorService automatically provides a pool of threads and an API for assigning tasks to it.
Use a ThreadPoolExecutor implementation and call getActiveCount() on it: int getActiveCount() // Returns the approximate number of threads that are actively executing tasks.
ExecutorService abstracts away many of the complexities associated with the lower-level abstractions like raw Thread . It provides mechanisms for safely starting, closing down, submitting, executing, and blocking on the successful or abrupt termination of tasks (expressed as Runnable or Callable ).
The only reasonable conclusion is that you (or the framework) are creating two references of ExecutorTest
and executing it twice.
Add the identityHashCode of the object to your logging.
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. As you can see the two values are different but if the ExecutorService
was creating two threads, those values would be the same.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With