Domanda

Ho il seguente semplice codice:

package main;

import java.util.concurrent.*;

public class Main {

    public static void main(String[] args) throws InterruptedException {
        new Main();
    }

    public Main() throws InterruptedException {
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
        executor.schedule(new MyRunnable(), 10, TimeUnit.SECONDS);
        System.out.println("Shutting down...");
        executor.shutdown();
        System.out.println("Awaiting termination...");
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
        System.out.println("Main finished!");
    }

    private class MyRunnable implements Runnable {
        public void run() {
            System.out.println("Finished running!");
        }
    }

}

In realtà, anche se il mio vero codice è un po' più complesso di così, potrei isolare il problema in quelle righe.Il codice attende sostanzialmente 10 secondi per eseguire l'eseguibile e quindi notifica la fine del programma principale.

Tuttavia, ho notato che per un periodo di 10 secondi uno dei miei core viene utilizzato al 100%.

Se commento questa riga:

executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);

Anche il core della CPU viene utilizzato al 100% e anche il programma principale termina prima del Runnable.

Se commento questa riga:

executor.shutdown();

La CPU è utilizzata correttamente ma il programma non termina.

Se commento entrambe le righe precedenti, la CPU viene utilizzata correttamente ma il programma principale non termina.

  1. C'è qualcosa di sbagliato nel mio codice?
  2. È executor.shutdown();Fai una sorta di impegnata in attesa invece di disabilitare la presentazione di nuovi compiti?
  3. O dovrei incolpare la JVM?

Ulteriori dettagli:

$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) Server VM (build 20.1-b02, mixed mode)

$ uname -a
Linux XPSG 2.6.32-5-686-bigmem #1 SMP Sun May 6 04:39:05 UTC 2012 i686 GNU/Linux

PS:Per favore, non chiedermi di usare a CountDownLatchnewSingleThreadScheduledExecutor.Ciò non è correlato alla domanda che sto ponendo.Grazie.

Modificare:

Ecco il dump Java:

Full thread dump Java HotSpot(TM) Server VM (20.1-b02 mixed mode):

"pool-1-thread-1" prio=10 tid=0x08780c00 nid=0x32ee runnable [0x6fdcc000]
   java.lang.Thread.State: RUNNABLE
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:943)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
    at java.lang.Thread.run(Thread.java:662)

"Low Memory Detector" daemon prio=10 tid=0x0874dc00 nid=0x32ec runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" daemon prio=10 tid=0x0874c000 nid=0x32eb waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" daemon prio=10 tid=0x0874a000 nid=0x32ea waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x08748800 nid=0x32e9 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=10 tid=0x0873a000 nid=0x32e8 in Object.wait() [0x70360000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x9e8f1150> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <0x9e8f1150> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x08735400 nid=0x32e7 in Object.wait() [0x703b1000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x9e8f1050> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <0x9e8f1050> (a java.lang.ref.Reference$Lock)

"main" prio=10 tid=0x086b5c00 nid=0x32e3 waiting on condition [0xb6927000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x9e958998> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2025)
    at java.util.concurrent.ThreadPoolExecutor.awaitTermination(ThreadPoolExecutor.java:1253)
    at main.Main.<init>(Main.java:19)
    at main.Main.main(Main.java:10)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)

"VM Thread" prio=10 tid=0x08731800 nid=0x32e6 runnable 

"GC task thread#0 (ParallelGC)" prio=10 tid=0x086bd000 nid=0x32e4 runnable 

"GC task thread#1 (ParallelGC)" prio=10 tid=0x086be400 nid=0x32e5 runnable 

"VM Periodic Task Thread" prio=10 tid=0x0874fc00 nid=0x32ed waiting on condition 

JNI global references: 931

Heap
 PSYoungGen      total 18752K, used 645K [0x9e8f0000, 0x9fdd0000, 0xb3790000)
  eden space 16128K, 4% used [0x9e8f0000,0x9e991510,0x9f8b0000)
  from space 2624K, 0% used [0x9fb40000,0x9fb40000,0x9fdd0000)
  to   space 2624K, 0% used [0x9f8b0000,0x9f8b0000,0x9fb40000)
 PSOldGen        total 42880K, used 0K [0x74b90000, 0x77570000, 0x9e8f0000)
  object space 42880K, 0% used [0x74b90000,0x74b90000,0x77570000)
 PSPermGen       total 16384K, used 2216K [0x70b90000, 0x71b90000, 0x74b90000)
  object space 16384K, 13% used [0x70b90000,0x70dba198,0x71b90000)
È stato utile?

Soluzione

Infatti è occupato ad aspettare.Sembra non esserci alcuna logica di backoff affinché ThreadPoolExecutor attenda fino al completamento di tutte le attività (Nota che questo si verifica solo quando tu shutdown() altrimenti sospenderà correttamente il thread).

Controlla continuamente se un'attività è pronta per essere eseguita, altrimenti riproverà finché non sarà trascorso il tempo trascorso per la pianificazione dell'attività.

Esiste un compromesso per la chiusura di un pool di thread pianificato (questo compromesso è imposto dall'implementazione).È necessario girare finché l'attività non è pronta per essere pianificata o shutdownNow dove nessuna attività in coda verrebbe eseguita.Tuttavia puoi prendere l'elenco dei Runnable restituiti ed eseguirli tu stesso.

Altri suggerimenti

Questo è un problema specifico della piattaforma. Quando ho eseguito il tuo programma di test sulla mia macchina, l'utilizzo della CPU era approssimativamente zero nel periodo di spegnimento di 10 secondi ... in base al monitoraggio dell'utilizzo della CPU della mia macchina.

$ java -version
java version "1.7.0_03"
Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
Java HotSpot(TM) Client VM (build 22.1-b02, mixed mode, sharing)
.

Ho fatto una ricerca curratoria del database Java Bugs, e non è stato presentato nulla di rilevante.

Guardando le diverse versioni del codice sorgente che puoi trovare in rete (Google), è chiaro che il metodo GetTask e gli amici hanno avuto un sacco di lavoro fatto su di loro tra (anticipato) Java 1.6 e (corrente ) Java 1.7.

Ti suggerisco di provare a aggiornare il tuo JVM all'ultima Java 1.6 oa Java 1.7. O almeno provarlo per il tuo programma di test. (O semplicemente vivi con esso. Questo è difficilmente uno spettacolo ...)


.

fyi, Questa pagina include istruzioni su come installare varie versioni di Java su Ubuntu.

    .
  • Un'opzione (per Java 7) è utilizzare il programma di installazione "Duinsoft" che è uno script che tira il programma di installazione dal sito Oracle. Hanno persino configurato un repository deb per ospitare l'installatore.

  • Un'altra opzione è installare i pacchetti OpenJDK-7-JDK o OpenJDK-7-JRE che sono nei repository 11.10

    E mentre sei nella zona, non dimenticare di votare su questo RFE su Fornisci il pacchetto / installatore Debian per Java 7.

    Per il record, questo casino è in gran parte un risultato di Oracle Ritirare la licenza per la ridistribuzione OEM che significa che il pacchetto" Sun-Java-6 "doveva essere ritirato. E, naturalmente, il "piccolo problema" che Oracle non fornisce Debs.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top