Domanda

Perché, oh perché non java.util.concurrent fornire una coda di indicatori di lunghezza per i suoi ExecutorServices? Recentemente mi sono trovato a fare qualcosa di simile:

ExecutorService queue = Executors.newSingleThreadExecutor();
AtomicInteger queueLength = new AtomicInteger();
...

public void addTaskToQueue(Runnable runnable) {
    if (queueLength.get() < MAX_QUEUE_LENGTH) {
        queueLength.incrementAndGet(); // Increment queue when submitting task.
        queue.submit(new Runnable() {
            public void run() {
                runnable.run();
                queueLength.decrementAndGet(); // Decrement queue when task done.
            }
        });
    } else {
        // Trigger error: too long queue
    }
}

Il che funziona bene, ma ... credo che questo in realtà dovrebbe essere implementato come una parte del ExecutorService. E 'muto e soggetto a errori da portare in giro un contatore separato dalla coda vera e propria, la cui lunghezza il contatore si suppone per indicare (mi ricorda matrici C). Ma, ExecutorServices sono ottenuti tramite metodi factory statici, quindi non c'è alcun modo per estendere semplicemente il resto eccellente esecutore singolo thread e aggiungere un contatore di coda. Quindi cosa devo fare:

  1. Reinventare roba già implementato in JDK?
  2. Altra soluzione intelligente?
È stato utile?

Soluzione

C'è un modo più diretto:

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newSingleThreadExecutor();
// add jobs
// ...
int size = executor.getQueue().size();

Anche se si potrebbe considerare di non utilizzare la comodità di creare metodi di esecutore, ma piuttosto creare direttamente l'esecutore di sbarazzarsi del cast e, quindi, essere sicuri che l'esecutore sarà sempre essere effettivamente un ThreadPoolExecutor, anche se l'attuazione di Executors.newSingleThreadExecutor sarebbe cambiare un giorno.

ThreadPoolExecutor executor = new ThreadPoolExecutor( 1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>() );

Questa è direttamente copiato da Executors.newSingleThreadExecutor in JDK 1.6. Il LinkedBlockingQueue che viene passato al costruttore è in realtà l'oggetto stesso che si ottiene indietro da getQueue.

Altri suggerimenti

Mentre è possibile controllare la dimensione della coda direttamente. Un altro modo di trattare con una coda che sta diventando troppo lunga sta facendo la coda interna delimitata.

public static
ExecutorService newFixedThreadPoolWithQueueSize(int nThreads, int queueSize) {
  return new ThreadPoolExecutor(nThreads, nThreads,
                              5000L, TimeUnit.MILLISECONDS,
                              new ArrayBlockingQueue<Runnable>(queueSize, true));
}

Questo farà sì che RejectedExecutionExceptions (vedi questo ) quando si supera il limite.

Se si vuole evitare l'eccezione thread chiamante può essere dirottato per eseguire la funzione. Vedere questa domanda SO per un soluzione.

Riferimenti

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