kirill_782
@kirill_782
Днем я Маринетт

Как усыпить поток до сигнала из другого потока?

Есть 2 потока. Они из общего массива берут один Runnable и выполняют его и убирают из массива. Из других потоков эти самые Runnable вставляются. Но при использовании wait и notify или ReentrantLock.Condition await/signal у меня IllegalMonitorStateException

package ru.irina.mongo;

import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;

import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MongoWorkers {

    private final static ArrayList<Runnable> tasks = new ArrayList<>();
    private final static ArrayList<DB> mongoDatabases = new ArrayList<>();
    private final static ArrayList<Worker> workers = new ArrayList<>();

    private static final Condition condition = new ReentrantLock().newCondition();

    public static void putTask(Runnable task) {
        synchronized (tasks) {
            tasks.add(task);
        }

        condition.signalAll();
    }

    public static void runWorkers(int threadCount) {

        if (!mongoDatabases.isEmpty())
            throw new IllegalStateException("Workers уже started");

        for (int i = 0; i < threadCount; ++i) {
            Worker worker = new Worker();
            worker.start();
            workers.add(worker);
        }

        System.out.println("[Worker] started " + threadCount + " threads");
    }

    public static DB getDB() {

        System.out.println("[Worker] request DB");

        synchronized (mongoDatabases) {
            if (!mongoDatabases.isEmpty()) {
                DB db = mongoDatabases.get(0);
                mongoDatabases.remove(0);
                return db;
            }

            return null;
        }
    }

    public static void returnDB(DB db) {

        System.out.println("[Worker] return DB");

        synchronized (mongoDatabases) {
            mongoDatabases.add(db);
        }
    }

    static class Worker extends Thread {
        Worker() {

            synchronized (mongoDatabases) {
                mongoDatabases.add(db);
            }

            setDaemon(true);
        }

        @Override
        public void run() {
            while (isAlive()) {
                Runnable runnable = null;

                synchronized (tasks) {
                    if (!tasks.isEmpty()) {
                        runnable = tasks.get(0);
                        tasks.remove(0);
                    }
                }

                if (runnable != null)
                    runnable.run();
                else {
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        // ...
                    }
                }

            }

        }
    }

}
  • Вопрос задан
  • 260 просмотров
Решения вопроса 2
sergey-gornostaev
@sergey-gornostaev Куратор тега Java
Седой и строгий
await и notify можно вызывать только на захваченном мониторе.
Ответ написан
Комментировать
@Dmtm
Android
почему бы не использовать защищенную очередь из concurent?
из головы забираем (сразу) и выполняем, в хвост - добавляем и не надо всего этого с wait и notify
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы