Синхронизация потоков с ThreadPoolExecutor - PullRequest
0 голосов
/ 20 марта 2011

Я пытаюсь реализовать некоторую логику, когда создаю основной (отчий) поток, который выполняет несколько других потоков. Затем он ожидает некоторого условия, которое создает дочерние потоки. После выполнения условия отец выполняет еще несколько дочерних потоков. Проблема в том, что когда я использую wait / notify, у меня есть исключение java.lang.IllegalMonitorStateException. Вот код:

public class MyExecutor {

final static ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(10);
final static ExecutorService svc = Executors.newFixedThreadPool(1);
static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 8, 10, TimeUnit.SECONDS, queue);

public static void main(String[] args) throws InterruptedException {
    final MyExecutor me =  new MyExecutor();
    svc.execute(new Runnable()  {
        public void run() {
            try {
                System.out.println("Main Thread");
                me.execute(threadPool, 1);
                System.out.println("Main Thread waiting");
                wait();
                System.out.println("Main Thread notified");
                me.execute(threadPool, 2);
                Thread.sleep(100);
                threadPool.shutdown();
                threadPool.awaitTermination(20000, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });

    svc.shutdown();
    svc.awaitTermination(10000, TimeUnit.SECONDS);
    System.out.println("Main Thread finished");
}

public void execute(ThreadPoolExecutor tpe, final int id) {
    tpe.execute(new Runnable()  {
        public void run() {
            try {
                System.out.println("Child Thread " + id);
                Thread.sleep(2000);
                System.out.println("Child Thread " + id + " finished");
                notify();
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
        }
    });
}

}

Когда я комментирую строку ожидания и уведомления, я получаю следующий вывод:
Основная тема
Основная тема ожидает
Основная тема уведомлена
Детская тема 1
Детская тема 2
Дитя 1 закончено
Детская тема 2 закончена
Основная тема закончена

1 Ответ

7 голосов
/ 20 марта 2011

В вашем коде есть ряд недостатков дизайна:


Вызов wait() и notify() должен происходить только в том случае, если вы являетесь владельцем блокировки объекта:

synchronized(foo) {
    foo.wait();
}

Вы вызываете wait() и notify() для разных объектов (внутренних классов!) - если один поток ожидает одного объекта, вы должны вызвать notify для того же самого объекта.


Существует вероятность пропущенного notify, когда это:

me.execute(threadPool, 1);

вызывается раньше wait - очень серьезный баг (возможны условия гонки).

Другие могут предложить вам использовать некоторые методы синхронизации более высокого уровня, но важно понять основы.

...