シナリオ
私はこのクラスを持っています。たとえばFoo
、その唯一の仕事は一連のタスクを順番に実行することです。シンプルに聞こえますよね?これらのタスクはすべて、独自の個別のスレッドで実行されます。Thread.join()
順次実行を確実にするために各タスクを単に呼び出す代わりに、それはとを使用ReentrantLock
しCondition
ます。例えば、
public class Foo
{
private final Lock lock;
private final Condition condition;
private Future<?> task;
public Foo()
{
lock = new ReentrantLock();
condition = lock.newCondition();
run();
}
/**
* Runs Foo
*/
public void run()
{
Runnable runnable = new Runnable()
{
@Override
public void run()
{
lock.lock();
try
{
// do tasks
}
finally
{
lock.unlock();
}
}
};
// Submit task
task = Executors.newSingleThreadExecutor().submit(runnable);
}
/**
* Blocks execution until signal is received
*/
public void waitForNotification()
{
try
{
condition.await();
}
catch (InterruptedException e)
{
}
}
/**
* Gets the lock
*
* @return Lock
*/
public final Lock getLock()
{
return lock;
}
/**
* Gets the condition
*
* @return Condition
*/
public final Condition getCondition()
{
return condition;
}
/**
* Gets the sender's task
*
* @return Task
*/
public Future<?> getTask()
{
return task;
}
}
すべてのタスクの後に、waitForNotification()
が呼び出され、別のクラス、たとえばBar
、それをウェイクアップするのを待ちます。の唯一の仕事は、タスクが成功したか失敗しBar
たかをアプリケーションに通知する応答を処理することです。そうは言っても、次の2つのいずれかを実行します。
- スレッドを完全にキャンセル
getTask().cancel
します(つまり) - スレッドをウェイクします(つまり
getCondition().signal
)
アイテム2は問題なく機能しますが、アイテム1は機能しません。例えば、
public class Bar
{
private Foo foo;
// doesn't work!
public void handleFailed()
{
// Cancel task
foo.getTask().cancel(true)
}
public void handlePassed()
{
// Signal waiting Foo
foo.getLock().lock();
try
{
foo.getCondition().signal();
}
finally
{
foo.getLock().unlock();
}
}
}
スレッドをキャンセルする代わりに、スレッドを中断しているように見えるためFoo
、実行が続行されます。冗長性については申し訳ありませんが、私は皆さんに明確な画像を提供したいと思いました。助言がありますか?