50 votes

Comment mettre en œuvre un threading simple avec un nombre fixe de threads de travail ?

Je cherche le moyen le plus simple et le plus direct de mettre en œuvre ce qui suit :

  • Le programme principal instancie le travailleur pour effectuer une tâche.
  • Seulement n peuvent être exécutées en même temps.
  • Quand n est atteint, plus aucun travailleur jusqu'à ce que le nombre de threads en cours d'exécution retombe en dessous de n .

56voto

erickson Points 127945

Je pense que Exécuteurs.newFixedThreadPool correspond à vos besoins. Il existe un certain nombre de façons différentes d'utiliser l'ExecutorService résultant, selon que vous souhaitez qu'un résultat soit renvoyé au thread principal, ou que la tâche soit totalement autonome, et selon que vous avez une collection de tâches à exécuter d'emblée, ou que les tâches sont mises en file d'attente en réponse à un événement quelconque.

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

Par ailleurs, si vous avez une nouvelle tâche asynchrone à exécuter en réponse à un événement quelconque, vous voudrez probablement utiliser la simple fonction d'exécution du service Executor. execute(Runnable) méthode.

25voto

Fabian Steeg Points 24261
/* 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(); }

7voto

Matt Points 1447

Executors.newFixedThreadPool(int)

Executor executor = Executors.newFixedThreadPool(n);

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

executor.execute(runnable);

2voto

hazzen Points 7315

Utiliser le cadre Executor, à savoir nouveauFixedThreadPool(N)

0voto

rjohnston Points 2450

Si vous voulez rouler le vôtre :

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

Où Worker est votre classe qui étend Thread. Chaque travailleur appelle la méthode removeWorker de cette classe, en se passant lui-même en paramètre, lorsqu'il a terminé son travail.

Cela dit, le cadre de l'Executor semble bien meilleur.

Edit : Quelqu'un peut expliquer pourquoi c'est si mauvais, au lieu de simplement le downmodder ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X