0

私は、さまざまなソースによってトリガーされるプロセスを持っています。シングルスレッド実行を適切に管理する方法は?

特定の条件下で他のプロセス(「manualStarter」と呼ぶ)がこのメインプロセスをトリガーしたい場合があるとします。メインプロセスには10秒〜10分かかるとします。 manualStarterが起動しようとしている間にプロセスがすでに進行中の場合は、複数回キューに入れてはいけません。メインプロセスの開始をトリガする2つ目のプロセスは、プロセスを一時的にトリガする「timedStarter」でもかまいませんが、プロセスが実行されていない場合にのみ実行されます。それはしばらくしてからもう一度。

これでisAlive()とjoin()を使用してこの種のプロセスマネージャを実装しようとしましたが、isAlive()は状態が生き残るまで、スレッドが開始されることがあります。だから私はそれに頼ることができなかったようだ。

次に、私が探しているものに近いところにあるSingleThreadExecutorサービスを試してみました。何もブロックしていないし、単一のスレッドしかプロセスを実行できないので、ステータスをチェックしたり、それを正しくロックしたり、スレッドを開始するキューが1より大きくならないようにするにはどうすればいいですか?私はセマフォがよく似たような種類のタスクに使用されていることを少しは読んだが、私はこのシナリオでどのように使用できるのでしょうか。

どのようにして私が望むものを達成することができますか?私自身のThreadPoolExecutorを実装する必要がありますか?どうしたらいいですか?もっと良い方法はありますか?

+1

// Schedule this to run periodically via ScheduledExecutorService class ManualStarter { private final AtomicBoolen isRunning = new AtomicBoolean(false); private ExecutorService exec = Executors.newSingleThreadedExecutor(); public void run() { if (!isRunning.getAndSet(true)) { // It wasn't running so this will start it exec.submit(new MainProcess(isRunning)); } } } class MainProcess extends Runnable { private final AtomicBoolean isRunning; MainProcess(AtomicBoolean isRunning) { this.isRunning = isRunning; } @Override public void run() { // do whatever it does isRunning.set(false); } } 

は、その後どこかには、定期的に何かをやって実行するための主なものをスケジュールします。 –

+0

@ワシアマドええ、私はそれが私が理解するために問題を抱えていることを信じています - どこでどのように使用するのですか? –

+0

ちょっと疑問:スレッドを起動しない方が簡単ではないかもしれませんが、いくつかのコマンドオブジェクトを**キュー**に追加するのは簡単でしょうか?言い換えれば、あなたの外部ソースからコマンドを同じキューに出力させるだけです。コンポーネントは定期的にそのキューの内容をスキャンし、そのスレッドを呼び出します(必要な場合)。ちょうど新しいコマンドを押して、キューは "ああ、私たちは現在実行されているので、1つは破棄することができます"という仕事をしていますか? – GhostCat

答えて

1

スレッドが実行されているかどうかを手動で確認できるように共有フラグを使用してください。例えば:あなたは、スレッドのためのあなたの所望の特性を達成するためにロックを使用して、同期して、いくつかのフラグを使用することができます

ScheduledExectorService sched = Executors.newScheduledThreadPool(1); 
ManualStarter starter = new ManualStarter(); 
// Every 10 seconds will check if MainProcess is running and will start 
// it if it's not 
sched..scheduleAtFixedRate(starter, 0, 10, SECONDS); 
+0

ええと、これはかなり現実的です。少なくとも最初の見解から、私はそれをよりよく理解しようとしていますが、それは想像していたかもしれませんが、実現する方法を知らなかったかもしれません。 –

+0

原子タイプの使用が有効です。これは他の答えでも見られた。 – byxor

+0

@ArturasMそれはそれを行うための単なる方法です。私は実際にこれを試していないことに注意してください。バグやコンパイルエラーがあっても驚くことはありませんが、うまくいけば大まかなアイデアを与えるのに十分です。 –

1

代わりにExecutorServiceを使用する必要があります。利用可能な実装がいくつかあります(ScheduledExecutorServiceなど)。これにより、defferedおよび/または繰り返されるタスクのスケジュールを設定できます(チェックExecutors)。あなたの最善のニーズに合ったものを選んでください。

条件付き実行に関しては、タスクは単純です。与えられたタスクの現在の "状態"を保持する、ある種のアクセス可能なフラグを定義します。実行中の場合は、何も実行しないでください。実行をスケジュールします。

簡単な例:任意のハウツーのために

//our flag 
private volatile AtomicBoolean isRunning=new AtomicBoolean(false); 

public void scheduleTask(){ 
    if(isRunning.get()){ 
     return; // do nothing 
}else{ 
    synchronized(isRunning){ 
    if(isRunning.get()){ 
     return; 
}else{ 
    isRunning.set(true) 
    scheduleNewTask(); 
} 
} 
} 
} 

は、私が「可変」ブール値を模擬するために、この例ではAtomicBooleanを使用していofficial Oracle's documentaion about Executors. をご確認ください。 booleanで行うこともできますが、別のオブジェクトで同期を行う必要があります(例えば、private Object lock=new Object();

+0

説明されている競合状態から解放されていません。 – Ivan

+0

SingleThreadExecutorはExecutorServiceです。アクセシブルフラグは私が現在苦労しているもので、効果的に設定する必要があるため、プロセスのトリガが要求されたら直ちにロックされ、プロセスの実行が終了するとロックが解除されるように設定する必要があります。 –

+0

@Ivanそれは - スケジューリング方法のシンプルな同期で、スレッドセーフです。 – Antoniossss

関連する問題