Как избежать блокировки многопоточной программы из-за ожидающих потоков

У меня есть модуль, который обрабатывает тысячи транзакций. Каждая транзакция имеет несколько этапов. Этот модуль выполняется в многопоточном режиме. Мы определили ограничения (жестко заданные) для количества потоков, которые он может создавать (ограничено в зависимости от использования сервера).

Теперь мы столкнулись с ситуацией, когда потокам может понадобиться подождать некоторое время (может быть более 24 часов). Поскольку количество потоков ограничено, и если все потоки ожидают более 24 часов, приложение полностью блокируется.

Что мне нужно здесь, как я должен повторно использовать поток, который находится в ожидании в течение 24 часов. если поток переходит в режим ожидания, мне нужно повторно использовать этот поток для другой транзакции, а когда исходное ожидание заканчивается, перезапустите исходную транзакцию с того места, где она была отложена.

Я надеюсь, что приведенное выше описание поможет вам понять проблему.

1 ответ

Если у вас большие задержки в вашей системе, лучше всего иметь больше потоков. Если вы хотите ограничить число одновременно работающих потоков, вы можете использовать разрешения, например, семафор, который высвобождается всякий раз, когда вы выполняете операцию блокировки, и повторно принимается, когда блокировка завершается. Это обеспечивает одновременное выполнение ограниченного числа потоков, но позволяет легко переключаться между многими задачами.

public abstract class LimitedTask implements Runnable {
    static final Semaphore PERMITS = new Semaphore(Runtime.getRuntime().availableProcessors());

    @Override
    public final void run() {
        try {
            PERMITS.acquire();
        } catch (InterruptedException e) {
            System.err.println("Task " + getClass() + " cancelled before it was started.");
            return;
        }
        try {
            runTask();
        } finally {
            PERMITS.release();
        }
    }

    protected abstract void runTask();

    protected void runBlockingTask(Runnable runnable) {
        PERMITS.release();
        try {
            runnable.run();
        } finally {
            PERMITS.acquireUninterruptibly();
        }
    }
}

В этом примере вы можете иметь столько их, сколько хотите, но только ограниченное число будет находиться в зоне РАЗРЕШЕНИЯ. Задачи также могут вызывать runBlockingTask(), чтобы позволить ему выполнить задачу блокировки, но позволить другому потоку работать во время блокировки.

Другие вопросы по тегам