Javaマルチスレッドのスケジュール動力ノードJava学院の整理
複数のスレッドがありますが、どのようにそれらの実行順序を制御しますか?
方法1:スレッド優先度を設定します。
java.lang.Threadは、SetPriority方法を提供してスレッドの優先度を設定していますが、スレッドの優先度はスレッドの実行順序を保障することができず、優先順位は優先度の高いスレッドのみがCPUリソースを取得する確率を高めるだけです。つまり、この方法はあてにならない。
方法二:スレッドを使って合併する。
java.lang.Threadのjoinを使用します。例えばスレッドaがありますが、現在のスレッドはaが実行されるのを待って下に進みたいです。a.join()を使ってもいいです。スレッドがa.join()を使用すると、現在のスレッドはaが消滅するのを待っています。いつaは消えますか?aのrun()方法の実行が終わったらaは消滅します。
この方法は効果的にスレッドスケジュールを行うことができるが、スレッドの実行スケジュールを待つだけに限定される。Nスレッドを待つなら、明らかに無力です。また、スレッドが消滅するのを待ってから実行を継続するコマンドが必要であり、2つのスレッドの真の意味での同時進行はできず、柔軟性が悪い。
方法3:スレッド通信を使用する。
java.lang.Objectはスレッド間通信が可能なwaitとnotify、notifyAllなどの方法を提供しています。各Javaオブジェクトには暗黙的なスレッドロックという概念があります。このスレッドロックの概念を通じてスレッド間で通信ができます。各スレッドはもうシングルに没頭しません。有名な「生産者-消費者」モデルはこの原理に基づいて実現されます。
この方法は効果的にスレッドスケジュールを行うこともでき,また一つのスレッドを待つ実行スケジュールに限らず,かなりの柔軟性がある。しかし、操作が複雑で、コントロールが難しく、混乱しやすく、プログラムのメンテナンスも不便です。
方法四:ロックを使う。
ロックはドアのように、事前の条件が満たされていない前にこのドアは閉じています。スレッドは通過できません。条件が決まったら、ロックが開かれます。スレッドは継続して実行できます。java.util.co ncurrent.count DownLatchは、countDown()とawait()の方法を提供しています。この方法は、MスレッドがNスレッドの実行終了を待って実行する場合に最適です。まず、CountDownLatchオブジェクトを初期化します。例えば、CountDownLatch doneSignal=new Count DownLatch(N);このオブジェクトは、Nをカウントしきい値として持ち、各待ちスレッドは、doneSignalオブジェクトの保有を通じて、count Down()を使用して、doneSignalのカウントしきい値を1つ減らすことができる。各待ちスレッドは、doneSignalオブジェクトの保有によって、await()を使って現在のスレッドをブロックし、doneSignalカウントしたしきい値が0になるまで、継続して実行します。
この方法は、効果的にスレッドスケジュールを行うこともでき、方法3より管理が容易であり、開発者はCountDownLatchを制御するだけでよい。しかし、スレッド実行順序は相対的に単一であり、現在の待ちスレッドの数を指摘するだけでなく、CountDownLatchの初期しきい値は設定すると減少してしまい、リセットできません。減算中にしたい場合は、しきい値のリセットは、java.util.co ncurrent.cclicBarrierを参照することができます。
いずれにしても、CountDownLatchは、ある条件のスレッド列の達成に役立つ。複雑な環境でのスレッド管理は効果的です。だから熟知して把握してその使用に対してやはり必要があります。
以下は実際のプロジェクトのCountDownLatchの使用例です。
もし読者が上記の例が明確ではないと感じたら、JDK APIから提供されたデモを参考にしてもいいです。
方法1:スレッド優先度を設定します。
java.lang.Threadは、SetPriority方法を提供してスレッドの優先度を設定していますが、スレッドの優先度はスレッドの実行順序を保障することができず、優先順位は優先度の高いスレッドのみがCPUリソースを取得する確率を高めるだけです。つまり、この方法はあてにならない。
方法二:スレッドを使って合併する。
java.lang.Threadのjoinを使用します。例えばスレッドaがありますが、現在のスレッドはaが実行されるのを待って下に進みたいです。a.join()を使ってもいいです。スレッドがa.join()を使用すると、現在のスレッドはaが消滅するのを待っています。いつaは消えますか?aのrun()方法の実行が終わったらaは消滅します。
この方法は効果的にスレッドスケジュールを行うことができるが、スレッドの実行スケジュールを待つだけに限定される。Nスレッドを待つなら、明らかに無力です。また、スレッドが消滅するのを待ってから実行を継続するコマンドが必要であり、2つのスレッドの真の意味での同時進行はできず、柔軟性が悪い。
方法3:スレッド通信を使用する。
java.lang.Objectはスレッド間通信が可能なwaitとnotify、notifyAllなどの方法を提供しています。各Javaオブジェクトには暗黙的なスレッドロックという概念があります。このスレッドロックの概念を通じてスレッド間で通信ができます。各スレッドはもうシングルに没頭しません。有名な「生産者-消費者」モデルはこの原理に基づいて実現されます。
この方法は効果的にスレッドスケジュールを行うこともでき,また一つのスレッドを待つ実行スケジュールに限らず,かなりの柔軟性がある。しかし、操作が複雑で、コントロールが難しく、混乱しやすく、プログラムのメンテナンスも不便です。
方法四:ロックを使う。
ロックはドアのように、事前の条件が満たされていない前にこのドアは閉じています。スレッドは通過できません。条件が決まったら、ロックが開かれます。スレッドは継続して実行できます。java.util.co ncurrent.count DownLatchは、countDown()とawait()の方法を提供しています。この方法は、MスレッドがNスレッドの実行終了を待って実行する場合に最適です。まず、CountDownLatchオブジェクトを初期化します。例えば、CountDownLatch doneSignal=new Count DownLatch(N);このオブジェクトは、Nをカウントしきい値として持ち、各待ちスレッドは、doneSignalオブジェクトの保有を通じて、count Down()を使用して、doneSignalのカウントしきい値を1つ減らすことができる。各待ちスレッドは、doneSignalオブジェクトの保有によって、await()を使って現在のスレッドをブロックし、doneSignalカウントしたしきい値が0になるまで、継続して実行します。
この方法は、効果的にスレッドスケジュールを行うこともでき、方法3より管理が容易であり、開発者はCountDownLatchを制御するだけでよい。しかし、スレッド実行順序は相対的に単一であり、現在の待ちスレッドの数を指摘するだけでなく、CountDownLatchの初期しきい値は設定すると減少してしまい、リセットできません。減算中にしたい場合は、しきい値のリセットは、java.util.co ncurrent.cclicBarrierを参照することができます。
いずれにしても、CountDownLatchは、ある条件のスレッド列の達成に役立つ。複雑な環境でのスレッド管理は効果的です。だから熟知して把握してその使用に対してやはり必要があります。
以下は実際のプロジェクトのCountDownLatchの使用例です。
private Map<Long,DecryptSignalAndPath> afterDecryptFilePathMap = new HashMap<Long,DecryptSignalAndPath>();//TODO
class DecryptRunnable implements Runnable {
private ServerFileBean serverFile;
private Long fid;//
private CountDownLatch decryptSignal;
protected DecryptRunnable(Long fid, ServerFileBean serverFile, CountDownLatch decryptSignal) {
this.fid = fid;
this.serverFile = serverFile;
this.decryptSignal = decryptSignal;
}
@Override
public void run() {
//
String afterDecryptFilePath = null;
DecryptSignalAndPath decryptSignalAndPath = new DecryptSignalAndPath();
decryptSignalAndPath.setDecryptSignal(decryptSignal);
afterDecryptFilePathMap.put(fid, decryptSignalAndPath);
afterDecryptFilePath = decryptFile(serverFile);
decryptSignalAndPath.setAfterDecryptFilePath(afterDecryptFilePath);
decryptSignal.countDown();//
}
}
class DecryptSignalAndPath {
private String afterDecryptFilePath;
private CountDownLatch decryptSignal;
public String getAfterDecryptFilePath() {
return afterDecryptFilePath;
}
public void setAfterDecryptFilePath(String afterDecryptFilePath) {
this.afterDecryptFilePath = afterDecryptFilePath;
}
public CountDownLatch getDecryptSignal() {
return decryptSignal;
}
public void setDecryptSignal(CountDownLatch decryptSignal) {
this.decryptSignal = decryptSignal;
}
}
先に実行する必要があります。スレッドがここに追加されるのを待っています。
CountDownLatch decryptSignal = new CountDownLatch(1);
new Thread(new DecryptRunnable(fid, serverFile, decryptSignal)).start();// , CountDownLatch
try {
decryptSignal.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
}
必要に応じて実行します。待ちスレッドはこのように参加できます。
CountDownLatch decryptSignal = afterDecryptFilePathMap.get(fid).getDecryptSignal();
try {
decryptSignal.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
}
もちろん、これは単にCountDownLatchの使用展示だけです。CountDownLatchにとってはちょっと役不足です。もっと複雑なマルチスレッド環境ができるからです。例の例では、スレッド通信を用いて完全に解決できます。CountDownLatchのしきい値は最初は1であるので、ここでは、方法二によるスレッドの結合を使って代えることもできる。もし読者が上記の例が明確ではないと感じたら、JDK APIから提供されたデモを参考にしてもいいです。
class Driver2 { // ...
void main() throws InterruptedException {
CountDownLatch doneSignal = new CountDownLatch(N);
Executor e = ...
for (int i = 0; i < N; ++i) // create and start threads
e.execute(new WorkerRunnable(doneSignal, i));
doneSignal.await(); // wait for all to finish
}
}
class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final int i;
WorkerRunnable(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}
public void run() {
try {
doWork(i);
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
以上は小编が皆さんに绍介したJavaマルチスレッドのスケジュールです。皆さんに何かお聞きしたいことがあれば、メッセージをください。小编はすぐに返事します。ここでも私たちのサイトを応援してくれてありがとうございます。