6

Ich habe einen Beispiel-Java-Code, unter dem, wenn als eine Konsole-Anwendung ausgeführt wird, verhält sich wie ich erwartet (spawning einen einzelnen Thread, um die ausführbare ausführen).Warum erzeugt der Java ExecutorService newSingleThreadExecutor zwei Threads?

Das seltsame Verhalten (spawning zwei Threads - Beispiel unten) Ich sehe ist, wenn ich dieses Beispiel als eine Dienstanwendung mit Apache prunsrv64.exe ausführen.

Ich teste dies auf einem Windows 7-Rechner - 64bit.

Beispielausgabe:

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 

Beispielcode:

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

      } 
     });  
    } 
} 

Dank.

Update: Nur um zu klären ich diesen Code nenne wie folgt:

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

Der gleiche Code ohne Änderungen verhält anders, wenn sie als Konsolenanwendung und eine Dienstanwendung ausgeführt werden, wie ich oben erwähnt.


Update 2: I gegeben, um eine zweite Testgerät, das eine ScheduledExecutorService verwendet. Das Verhalten ist das gleiche.

Update2 Ausgang:

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 Protokollierung Identität 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 
+0

Wahrscheinlich rufst du 'testIt' schon zweimal an? –

+0

Ich würde annehmen, dass Ihr Hauptthread das Programm ausführt, und dann erstellen Sie die 'Executors.newSingleThreadExecutor();' die einen anderen Thread erstellt. Daraus ergeben sich zwei Threads. –

+0

Erhalten Sie 2 verschiedene Thread-IDs, wenn Sie einen Ausdruck von getId() direkt vor der while-Schleife platzieren? – brummfondel

Antwort

4

Die einzige vernünftige con hinzufügen Schlussfolgerung ist, dass Sie (oder das Framework) zwei Referenzen von ExecutorTest erstellen und zweimal ausführen.

Fügen Sie der Protokollierung den identityHashCode des Objekts hinzu.

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

Der gleiche Code ohne Änderungen verhält anders, wenn sie als Konsolenanwendung und eine Dienstanwendung ausgeführt werden, wie ich oben erwähnt.

Sie steuern genau, wie viele hier erstellt werden.


bearbeiten Basierend auf dem dritten Update.

Meine Annahme ist richtig, die System.identityHashCode eines Objekts ist analog zu seinem Speicherort. Wie Sie sehen können, sind die beiden Werte unterschiedlich, aber wenn die ExecutorService zwei Threads erstellt, sind diese Werte identisch.

Das bedeutet, dass Sie mehrere Instanzen erstellen. Vielleicht nicht direkt, aber das Framework erstellt mehrere gleiche Dienste und führt sie aus.

Das geht also von einer Frage aus, "warum der Executor-Service zwei Threads erstellt" zu "warum ist mein Framework zwei Service-Instanzen erstellen". Diese Frage kann ich nicht beantworten.

deutlicher Um zu klären, stellen Sie sich Ihren Test wie diese

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

Ausführung, die ähnlich ist, was in Ihrer Anwendung auftritt.

+0

John, ich habe die Protokollierung geändert. Bitte siehe Update 3. –

+0

@tintsi Danke, ich werde eine Bearbeitung basierend darauf machen. –

+0

Es scheint, dass eine zweite Referenz nicht in meinem Code erstellt wird: Referenz: 1939972532 –

1

Ich habe versucht, tatsächlich diesen Code in meinem PC wie diese,

 

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

und ich bin nur ein Thread bekommen,

 
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 meist kann ein Fehler auf dem Weg Sie instanziieren sind die Klasse