Как заставить ThreadPoolExecutor немедленно выполняться в Java - PullRequest
2 голосов
/ 09 октября 2019

У меня есть ThreadPoolExecutor и Runnable, называемые this.runnable. Я запускаю это так:

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
executor.execute(this.runnable);

Обычно this.runnable будет вызываться почти сразу (через 100-200 мкс). Но иногда, если процессор занят, запуск может занять некоторое время.

Есть ли способ, которым я могу "принудительно" выполнить это немедленно или предложить JVM / ThreadPoolExecutor назначить приоритет выполнению этого потока? Мне нужно сохранить его как отдельный поток, но в то же время мне нужно, чтобы он начал работать срочно.

Ответы [ 2 ]

1 голос
/ 09 октября 2019

Вы можете использовать PriorityBlockingQueue для постановки задач в очередь. Таким образом, задаче с высоким приоритетом может быть предоставлено самое высокое место в очереди, поэтому она выполняется, как только рабочий освобождается. Но мне не нравится эта опция, потому что она добавляет усложнение и накладные расходы, и задачи с низким приоритетом могут быть истощены.

Перебор с приоритетами потоков обычно не работает хорошо. Разные платформы реализуют разные уровни приоритетов, поэтому код, опирающийся на приоритеты, может работать по-разному на разных платформах. Кроме того, наличие разных потоков приоритетов позволяет легко вызвать ошибку инверсии приоритетов . Вот что книга Параллелизм Java на практике (10.3.1) говорит о приоритетах:

Обычно разумно сопротивляться искушению настроить приоритеты потоков. Как только вы начинаете изменять приоритеты, поведение вашего приложения зависит от платформы, и вы рискуете голодать. Вы часто можете обнаружить программу, которая пытается восстановиться после настройки приоритета или других проблем с отзывчивостью по наличию вызовов Thread.sleep или Thread.yield в нечетных местах, пытаясь выделить больше времени для потоков с более низким приоритетом.

Как уже говорили другие, вы не можете запретить другим процессорам использовать ЦП (вам придется переместить ваше приложение на платформу, где оно не конкурирует с другими процессами за ЦП), и вы можетене заставлять ОС планировать и запускать определенный поток.

Вам не нужно ограничивать себя одним пулом потоков, иногда есть веские причины иметь несколько пулов . JCIP (8.1) рекомендует:

Пулы потоков работают лучше всего, когда задачи однородны и независимы. Смешивание долгосрочных и краткосрочных задач может привести к «засорению» пула, если он не очень большой;отправка задач, зависящих от других задач, может привести к тупиковой ситуации, если пул не ограничен.

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

Что бы я сделал:

  • Сначала убедитесь, что пул потоков инициализируется только один раз, при запуске, иотрегулируйте размер пула потоков, чтобы иметь более одного потока. С одним потоком ваша задача может быть просто заблокирована за другим.

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

  • Если пул по-прежнему является узким местом, создайте отдельный пул потоков для использования в качестве быстрой полосы для задач с высоким приоритетом.

1 голос
/ 09 октября 2019

Есть ли способ, которым я могу "принудительно" выполнить это немедленно или предложить JVM / ThreadPoolExecutor назначить приоритет выполнению этого потока?

Нет. Кроме того, после запуска потока у вас нет возможности контролировать, как он продолжает работать. Вам разрешено устанавливать индивидуальный приоритет потока, но это полезно только тогда, когда JVM решает, запускать ли ваш поток или какой-либо другой поток, возможно, с более низким приоритетом - он не позволяет вам запускать поток в любое время или по своему усмотрению.

Специально для ThreadPoolExecutor, когда вы вызываете execute() в экземпляре ThreadPoolExecutor, Javadoc говорит: "Выполняет заданную задачу когда-нибудь в будущем." Нет упоминания о том, как повлиять или контролировать , когда поток начнется.

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

Возможно, вы могли бы создать пул потоков с одним (или более) потоками, готовыми к работе, и использовать что-то из встроенных классов параллелизма Java (таких как ). Семафор ) как способ начать выполнение.

ОБНОВЛЕНИЕ : Вот пример, показывающий, как вы можете использовать семафор для "запуска" потока.

Semaphore semaphore = new Semaphore(0);
new SomeThread(semaphore).start();

// do other things for a while

// when you're ready for the thread to actually start, call "release()" 
semaphore.release();

вот ччитайте сами - он принимает Semaphore в качестве ввода, затем ждет, пока он не сможет успешно получить его, прежде чем перейти к следующему коду:

class SomeThread extends Thread {
    private Semaphore semaphore;

    SomeThread(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            semaphore.acquire();
            // TODO: do the actual thread work here
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
...