Предположим, у меня есть ExecutorService (который может быть пулом потоков, поэтому существует параллелизм), который выполняет задачу в разное время, либо периодически, либо в ответ на какое-то другое условие. Задача, которую нужно выполнить, следующая:
- если эта задача уже выполняется, ничего не делать (и позволить завершиться ранее выполненной задаче).
- если эта задача еще не выполняется, запустите алгоритм X, который может занять много времени.
Я пытаюсь придумать, как это реализовать. Это должно быть что-то вроде:
Runnable task = new Runnable() {
final SomeObj inProgress = new SomeObj();
@Override public void run() {
if (inProgress.acquire())
{
try
{
algorithmX();
}
finally
{
inProgress.release();
}
}
}
}
// re-use this task object whenever scheduling the task with the executor
где SomeObj
- это либо ReentrantLock (приобретать = tryLock()
и выпуск = unlock()
), либо AtomicBoolean или что-то еще, но я не уверен, какой именно. Мне нужен ReentrantLock здесь? (Может быть, я хочу блокировку без повторного входа в случае, если algorithmX()
вызывает рекурсивное выполнение этой задачи!) Или будет достаточно AtomicBoolean?
edit: для одноразовой блокировки это уместно?
Runnable task = new Runnable() {
boolean inProgress = false;
final private Object lock = new Object();
/** try to acquire lock: set inProgress to true,
* return whether it was previously false
*/
private boolean acquire() {
synchronized(this.lock)
{
boolean result = !this.inProgress;
this.inProgress = true;
return result;
}
}
/** release lock */
private void release() {
synchronized(this.lock)
{
this.inProgress = false;
}
}
@Override public void run() {
if (acquire())
{
// nobody else is running! let's do algorithmX()
try
{
algorithmX();
}
finally
{
release();
}
}
/* otherwise, we are already in the process of
* running algorithmX(), in this thread or in another,
* so don't do anything, just return control to the caller.
*/
}
}