. если у меня есть пул потоков из двух потоков, но хочу, чтобы каждый поток был посвящен одному типу задачи. то есть задача 1 может выполняться только в потоке 1 пула, задача 2 в потоке 2 пула. Я не хочу больше двух потоков, и я не хочу, чтобы две задачи (ы) запускались одновременно (по одному на каждый поток). Возможное??Как убедиться, что одна задача Runnable не работает одновременно на двух потоках
ответ
Если вы хотите убедиться, что одна задача не выполняется в два раза, в то же время, использовать boolean
, чтобы указать, что задача выполняется или нет:
(Java 8+)
volatile boolean task1Running = false;
Runnable task1 =() -> {
if(task1Running)
return; //already running, exit
task1Running = true;
//handle task
task1Running = false;
};
Теперь, когда вы пытаетесь выполнить его, пока он уже запущен, он выйдет. volatile
должен гарантировать, что при изменении task1Running
из темы, управляющей этой задачей, все остальные потоки (в частности, поток, выполняющий задачи) сразу увидят.
Я должен, возможно, упомянуть, что 'volatile' здесь не помогает, так как все еще возможно, что два потока прочитали неизмененную переменную, чтобы решить, должны ли они вернуться раньше, поэтому, если они видят это как ложные, они продолжаются, устанавливая для нее значение true first и позже к ложному. Между заданием чтения1Runnig и письмом есть короткий промежуток времени. Это единственный способ избежать этого - это атомный CompareAndSet, как это предусмотрено AtomicBoolean. Это позволит устранить короткий разрыв между тестом и множеством. Летучие только gurantees, что чтение task1Running происходит после любой записи. Он не закрывает промежуток времени. –
@ RalfH "* Чтение и запись являются атомарными для всех объявленных переменных volatile *" - [Atomic Access] (https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html) Ум, удаляющий нижний предел? –
Прочтите мой комментарий еще раз.Конечно, первое чтение 'task1Running' является атомарным, что означает, что вся переменная извлекается из памяти за одну операцию. То же самое для любой записи. Ссылка на атомный доступ для чтения и записи из памяти. На некоторых архитектурах чтение/запись для 64-битных значений может быть разделено на две области памяти и получить неопределенные результаты за время между этими двумя обращениями. Здесь не проблема. –
Нет, невозможно. Это преимущество использования пула потоков: пул будет выбирать, какой поток будет выполнять поставленную задачу. Обратите внимание, что даже если вы используете Executors#newFixedThreadPool(2)
, у вас будет пул потоков с двумя потоками, но это не гарантирует, что каждая задача выполняется в другом потоке.
Если вам нужно, чтобы ваши задачи выполнялись в разных конкретных потоках, вместо этого создайте свои собственные потоки. Если вы не хотите создавать потоки вручную, используйте 2 однопоточных исполнителей. Вы можете создать их, используя Executors#newSingleThreadExecutor
(но это очень громоздко).
Спасибо за ответ. То, что я делаю в настоящее время. Надеюсь, что будет лучший способ. – Cm57201
Хотя уже есть принятый ответ, вы должны использовать AtomicBoolean
вместо volatile
. Как в
AtomicBoolean task1RunningAB = new AtomicBoolean(false);
Runnable task1 =() -> {
// compareAndSet(E, N) sets the value to N if current value matches E.
// Returns true if that was the case, so we must negate here
if (! task1RunningAB.compareAndSet(false, true))
return;
try {
// your code
} finally {
task1RunningAB.set(false);
}
};
Почему это вопрос, какая нить используется в бассейне? –
Не имеет значения, какой поток будет использоваться в пуле для обслуживания какой задачи. Просто, что две задачи1 не должны запускаться одновременно. Также я не могу контролировать порядок выполнения заданий. Любые идеи о том, как заставить его работать? Я должен иметь только два потока одновременно. Больше. – Cm57201
Затем создайте 'boolean' для каждой задачи, указав, работает оно или нет. Обе задачи должны сначала проверить, запущен ли он (проверьте логическое значение). Если нет, установите для boolean значение true и продолжите. Если ваша задача уже запущена и она выполняется снова, itll выйдет, поскольку логическое значение true (уже запущено). Убедитесь, что задача только exexutes, если она еще не запущена –