Pergunta

Eu estou procurando a maneira mais simples, mais simples de implementar o seguinte:

  • O programa principal instancia trabalhador tópicos para fazer uma tarefa.
  • Apenas tarefas n pode estar em execução ao mesmo tempo.
  • Quando n é atingido, não mais trabalhadores são iniciados até que a contagem de correndo tópicos cai para trás abaixo n.
Foi útil?

Solução

Eu acho que Executors.newFixedThreadPool adapta às suas necessidades. Há um número de diferentes maneiras de usar o ExecutorService resultante, dependendo se você quer um resultado retornado para o segmento principal, ou se a tarefa é totalmente auto-suficiente, e se você tem uma coleção de tarefas a executar na frente, ou se as tarefas são enfileiradas em resposta a algum evento.

  Collection<YourTask> tasks = new ArrayList<YourTask>();
  YourTask yt1 = new YourTask();
  ...
  tasks.add(yt1);
  ...
  ExecutorService exec = Executors.newFixedThreadPool(5);
  List<Future<YourResultType>> results = exec.invokeAll(tasks);

Como alternativa, se você tem uma nova tarefa assíncrona para executar em resposta a algum evento, você provavelmente só quer utilizar o método execute(Runnable) simples do ExecutorService.

Outras dicas

/* Get an executor service that will run a maximum of 5 threads at a time: */
ExecutorService exec = Executors.newFixedThreadPool(5);
/* For all the 100 tasks to be done altogether... */
for (int i = 0; i < 100; i++) {
    /* ...execute the task to run concurrently as a runnable: */
    exec.execute(new Runnable() {
        public void run() {
            /* do the work to be done in its own thread */
            System.out.println("Running in: " + Thread.currentThread());
        }
    });
}
/* Tell the executor that after these 100 steps above, we will be done: */
exec.shutdown();
try {
    /* The tasks are now running concurrently. We wait until all work is done, 
     * with a timeout of 50 seconds: */
    boolean b = exec.awaitTermination(50, TimeUnit.SECONDS);
    /* If the execution timed out, false is returned: */
    System.out.println("All done: " + b);
} catch (InterruptedException e) { e.printStackTrace(); }

executores. newFixedThreadPool (int)

Executor executor = Executors.newFixedThreadPool(n);

Runnable runnable = new Runnable() {
 public void run() {
  // do your thing here
 }
}

executor.execute(runnable);

Use o quadro Executor; nomeadamente newFixedThreadPool (N)

  1. Se a sua fila tarefa não vai ser ilimitada e tarefas podem terminar em intervalos de tempo mais curtos, você pode usar Executors.newFixedThreadPool(n); como sugere pelos especialistas.

    A única desvantagem desta solução é o tamanho da fila de tarefas ilimitada. Você não tem controle sobre ele. A enorme engavetamento na fila de tarefas irá degradar o desempenho de aplicação e pode causar falta de memória em alguns cenários.

  2. Se você quiser usar ExecutorService e permitir work stealing mecanismo onde threads de trabalho ociosos compartilhar a carga de trabalho de segmentos de trabalho ocupados por roubar tarefas na fila de tarefas. Ele irá retornar tipo ForkJoinPool de Serviço Executor.

    ExecutorService newWorkStealingPool public static (int paralelismo)

    Cria um pool de threads que mantém tópicos suficientes para apoiar a determinado nível de paralelismo, e pode usar várias filas para reduzir a contenção. Os corresponde nível paralelismo para o número máximo de segmentos que participam activamente na, ou disponíveis para engatar em, processamento de tarefas. O número real de tópicos pode aumentar e diminuir dinamicamente. Um pool de roubo de trabalho não faz nenhuma garantia sobre a ordem em que apresentou as tarefas são executadas.

  3. Eu prefiro ThreadPoolExecutor devido à flexibilidade de APIs para controlar muitos paratmeters, que controla a execução da tarefa de fluxo.

    ThreadPoolExecutor(int corePoolSize, 
                           int maximumPoolSize, 
                           long keepAliveTime, 
                           TimeUnit unit, 
                           BlockingQueue<Runnable> workQueue, 
                           ThreadFactory threadFactory,
                           RejectedExecutionHandler handler)
    

No seu caso, definir tanto corePoolSize and maximumPoolSize as N. Aqui você pode controlar o tamanho da fila de tarefas, definir a sua própria política de fábrica de fio personalizado e manipulador de rejeição.

Tenha um olhar em questão SE relacionado para controlar o tamanho do conjunto de forma dinâmica:

Tópico dinâmico Piscina

Se você desejar construir sua própria:

private static final int MAX_WORKERS = n;
private List<Worker> workers = new ArrayList<Worker>(MAX_WORKERS);

private boolean roomLeft() {
    synchronized (workers) {
        return (workers.size() < MAX_WORKERS);
    }
}

private void addWorker() {
    synchronized (workers) {
        workers.add(new Worker(this));
    }
}

public void removeWorker(Worker worker) {
    synchronized (workers) {
        workers.remove(worker);
    }
}

public Example() {
    while (true) {
        if (roomLeft()) {
            addWorker();
        } 
    }
}

Onde Trabalhador é a sua classe que estende Thread. Cada trabalhador irá chamar o método removeWorker desta classe, passando-se como um parâmetro, quando terminou a fazê-lo de coisa.

Com o que disse, o quadro Executor parece muito melhor.

Edit:? Qualquer um cuidado de explicar por que isso é tão ruim, em vez de apenas downmodding it

Como outros aqui mencionados, a sua melhor aposta é fazer um pool de threads com o Executores classe:

No entanto, se você desejar construir sua própria, este código deve dar uma idéia de como proceder. Basicamente, basta adicionar cada novo segmento para um grupo de discussão e certifique-se que você nunca tem mais de N tópicos ativos do grupo:

Task[] tasks = getTasks(); // array of tasks to complete
ThreadGroup group = new ThreadGroup();
int i=0;
while( i<tasks.length || group.activeCount()>0 ) {
    if( group.activeCount()<N && i<tasks.length ) {
        new TaskThread(group, tasks[i]).start();
        i++;
    } else {
        Thread.sleep(100);
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top