Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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).

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
like image 925
tint si Avatar asked Dec 04 '14 15:12

tint si


People also ask

How do I stop all threads in ExecutorService?

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() .

What is ExecutorService in multithreading in Java?

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.

How do I find the number of threads in ExecutorService?

Use a ThreadPoolExecutor implementation and call getActiveCount() on it: int getActiveCount() // Returns the approximate number of threads that are actively executing tasks.

What are the advantages of using ExecutorService instead of creating threads directly?

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 ).


1 Answers

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.

like image 71
John Vint Avatar answered Sep 30 '22 18:09

John Vint