2013-04-12 22 views
7

Come posso controllare se un thread è in esecuzione nel pool di thread ExecutorService?Come verificare se un thread è in esecuzione nel pool di thread ExecutorService

Sfondo:
Voglio sincronizzarmi tra i thread nel pool di thread se c'è un flag impostato. Quindi se il flag è impostato su true per la sincronizzazione, allora devo controllare se altri thread sono in esecuzione o attendere il suo completamento e quindi richiamare il thread di blocco con synchronize, in modo che altri thread attenderanno il completamento del thread di blocco.

Se flag non è impostato, non è necessario sincronizzare e potrebbe eseguire i thread in parallelo.

Grazie!

+1

Ci può dare qualche contesto di ciò che/perché stai facendo? –

+0

provato thread.isAlive()? – Ankit

+0

Cosa intendi? Intendi se un _task_ è in esecuzione? Ci sarà sempre 'Threads' vivo in un' ExecutorService'. Per favore pubblica il tuo codice in modo che possiamo aiutarti piuttosto che indovinare ciò di cui potresti aver bisogno. –

risposta

5

È necessario utilizzare un Semaphore.

Ciò consente di avere un numero di "permessi" per eseguire il lavoro. Se si desidera eseguire una sola attività alla volta, è necessario disporre di un numero Semaphore con un permesso, oppure disporre di un numero Semaphore con un numero di autorizzazioni superiore al numero di Thread s nel pool.

static class Worker implements Runnable { 

    final Semaphore semaphore; 

    public Worker(Semaphore semaphore) { 
     this.semaphore = semaphore; 
    } 

    @Override 
    public void run() { 
     try { 
      semaphore.acquire(); 
      try { 
       //do stuff 
      } finally { 
       semaphore.release(); 
      } 
     } catch (InterruptedException ex) { 
      Thread.currentThread().interrupt(); 
     } 
    } 
} 

public static void main(String[] args) { 

    final int numThreads = 10; 
    final ExecutorService executorService = Executors.newFixedThreadPool(10); 
    final Semaphore semaphore; 
    boolean myflag = true; 
    if (myflag) { 
     semaphore = new Semaphore(1); 
    } else { 
     semaphore = new Semaphore(numThreads); 
    } 
    final Worker worker = new Worker(semaphore); 
    executorService.submit(worker); 
} 

Questo esempio è un po 'forzato, come si può semplicemente utilizzare un newSingleThreadExecutor() quando è necessario un solo compito da eseguire in un momento - ma suppongo si sa che per qualche ragione non riesce.

EDIT

Dopo aver curiosato un po 'per vedere se questo può essere riordinata mi sono imbattuto in this. Questo allude a una soluzione più ordinato:

static interface TaskBlocker { 

    void acquire(); 

    void release(); 
} 

static class Worker implements Runnable { 

    final TaskBlocker taskBlocker; 

    public Worker(TaskBlocker taskBlocker) { 
     this.taskBlocker = taskBlocker; 
    } 

    @Override 
    public void run() { 
     taskBlocker.acquire(); 
     try { 
      //do stuff 
     } finally { 
      taskBlocker.release(); 
     } 
    } 
} 

public static void main(String[] args) { 

    final int numThreads = 10; 
    final ExecutorService executorService = Executors.newFixedThreadPool(numThreads); 
    final TaskBlocker taskBlocker; 
    boolean myflag = true; 
    if (myflag) { 
     taskBlocker = new TaskBlocker() { 
      final Lock lock = new ReentrantLock(); 

      @Override 
      public void acquire() { 
       lock.lock(); 
      } 

      @Override 
      public void release() { 
       lock.unlock(); 
      } 
     }; 
    } else { 
     taskBlocker = new TaskBlocker() { 
      @Override 
      public void acquire() { 
      } 

      @Override 
      public void release() { 
      } 
     }; 
    } 
    final Worker worker = new Worker(taskBlocker); 
    executorService.submit(worker); 
} 
+0

Hai lo stesso effetto con un SingleThreadExecutor? – Bhargav

+0

@Bhargav quale effetto? –

+0

Lo sai. assicurandoti che solo 1 task sia in esecuzione in un dato momento – Bhargav

3

In breve, non è così. Gli esecutori non sono pensati per essere usati in questo modo. Se vuoi gestire i tuoi thread manualmente, fallo senza Executor. Se usi Executor, sposta il tuo pensiero da Thread a Runnable s. Rendi i tuoi Runnables o le Classi e i metodi sicuri per il thread, usando la sincronizzazione o una qualsiasi delle astrazioni di alto livello in java.util.concurrent.

3

Come posso controllare se un thread è in esecuzione nel pool di filo ExecutorService?

Questo in realtà non ha senso nel contesto di un pool di thread ExecutorService. Il pool sta eseguendo le classi Runnable (o Callable). Forse quello che dovresti chiedere è se puoi vedere se un determinato lavoro è in esecuzione o no.

Se si vuole realizzare questo allora ciascuno dei posti di lavoro, nella parte anteriore del metodo run() (o call()) può controllare una sorta di synchronized oggetto e attendere o continuare, se necessario. Potrebbe anche essere che potresti avere più pool di thread e dividere i tuoi lavori in parti più piccole in modo da poter controllare quali parti dei tuoi lavori vengono eseguite contemporaneamente.

Tuttavia, in generale, come sottolinea @Ralf, ciò che si sta facendo è contro l'intero punto del pool di thread. L'intero punto dei pool di thread è che i processi vengono eseguiti in modo asincrono. Se hai bisogno di molti punti di sincronizzazione allora forse hai bisogno di riprogettare.

Se si forniscono maggiori dettagli sul proprio ambiente, potremmo essere in grado di affrontare in modo più specifico la domanda sottostante.

+0

Qualcuno vuole aggiungere feedback sul downvote? – Gray

3

Come posso controllare se un thread è in esecuzione nel pool di thread ExecutorService?

Se si vuole solo sapere se un thread è in esecuzione in una specifica ExecutorService, è possibile creare il ExecutorService con una specifica ThreadFactory e lo hanno allegare qualche proprietà speciale al filo, come ad esempio un nome speciale.

private static final String EXECUTOR_THREADNAME_PREFIX = "ExecutorThread"; 

ThreadFactory threadFactory = new ThreadFactory() { 

    private final AtomicInteger id = new AtomicInteger(0); 

    @Override 
    public Thread newThread(Runnable r) { 
     Thread thread = new Thread(r); 
     thread.setName(EXECUTOR_THREADNAME_PREFIX + "_" + id.incrementAndGet()); 
     return thread; 
    } 
}; 

myExecutor = Executors.newCachedThreadPool(threadFactory); 

Poi, nel thread, è sufficiente verificare se il nome inizia con il prefisso:

if (Thread.currentThread().getName().startsWith(EXECUTOR_THREADNAME_PREFIX)) { 
    // In executor. 
} else { 
    // Not in executor. 
} 
Problemi correlati