JAVA進級シリーズ-同時プログラミング-第5編Thread API
8711 ワード
前編ではThreadクラスの構造方法を紹介しましたが、構造方法だけでは足りません.このクラスでよく使われるAPIをもっと勉強しなければなりません.そうすれば、このクラスをもっと深く理解することができ、同時により多くの選択をすることができます.
Threadクラスが提供するAPIは数十個あり,紙面の問題のため,本論文では代表的なものをいくつか選択して説明する.残りのAPIの仲間たちが興味を持っているのはソースコードで調べることができて、私に伝言を与えることができて、私たちは共同で勉強することを検討します.
ターゲット currentThread setPriority yield sleep interrupt interrupted join
内容
1. currentThread
この方法は、現在の実行スレッドの参照を返すために使用され、コードブロックで現在のスレッドオブジェクトを取得することができます.簡単に見えますが、非常に広く使用されており、後続のコンテンツで多く使用されます.
方法:
コード:
2. setPriority
プロセスにはプロセスの優先度があり,スレッドにも優先度があり,理論的には優先度の高いスレッドはCPUによって優先的にスケジューリングされるが,実際には望ましくないことが多い.
CPUが忙しい場合、優先度を設定するとより多くのCPUタイムスライスが得られる可能性がありますが、CPUが空いている場合、優先度を設定することはほとんど役に立ちません.したがって、プログラム設計で優先度を使用して特定のビジネスをバインドしたり、ビジネスを優先度に依存させたりしようとしないでください.この結果は、あなたが望む結果と一致しない可能性があります.
方法:
ケース:
3. yield
yieldメソッドは、スケジューラに現在のスレッドがプロセッサの現在の使用を放棄することを示す啓発的なメソッドに属します.スケジューラは、このプロンプトを無視できます.詳細なパフォーマンス分析とベンチマークテストと組み合わせて、実際に必要な効果があることを確認する必要があります.
この方法はあまり使われていません.デバッグまたはテストの目的では、競合条件によるエラーの再現に役立つ可能性があります.
方法:
ケース:
4. sleep
sleepは、システムタイマとスケジューラの精度と正確性に基づいて、現在実行中のスレッドを指定したミリ秒数までスリープ状態(一時的に実行を停止)にします.このスレッドはモニタの所有権を失うことはありません(例えばmonitorロック、monitorロックについては後述します).
方法:
ケース:
yieldとsleepの違い: yieldはCPUスケジューラに対するヒントにすぎず、有効になるとスレッドコンテキストの切り替えを招く. sleepは現在のスレッドが指定した時間を一時停止し、CPUタイムスライスの消費がない. yieldはスレッドをRUNNING状態からRUNNABLE状態にする. sleepはスレッドを短いblockにし、その後、所定の時間内にCPUリソースを解放する. yieldは一定の有効性を保証できないが、sleepはほぼ100%所定の時間に従ってスリープする(最終スリープ時間はシステムのタイマとスケジューラの精度に準じる) . yieldは割り込み信号をキャプチャすることができず、sleepは別のスレッドによって割り込み信号 をキャプチャすることができる.
5. interrupt
スレッドinterruptは非常に重要なAPIであり、呼び出された場合、よく使用される方法でもあります. Objectクラスのwait()、wait(long)またはwait(long,int)メソッドまたはjoin()、join(long)、join(long,int)メソッドの場合、このスレッドはブロックされ、このようなsleep(long)またはsleep(long,int)メソッドの場合、その中断状態はクリアされ、 InterruptibleChannelのI/Oが動作すると、チャネルは閉じられ、スレッドの割り込み状態が設定され、スレッドは Selectorのwakeupメソッドでは、スレッドの割り込み状態が設定され、セレクタの起動方法を呼び出すように、選択操作からすぐに戻ります(ゼロ以外の値がある場合があります).
これに関連するAPIはまだいくつかあります.
方法:
ケース:
スレッドの内部には
しかし、現在のスレッドが割り込み可能なメソッドを実行している場合、
7. join
Threadのjoin法も同様に非常に重要な方法であり,その特性を用いて多くの比較的強い機能を実現することができ,Threadクラスでは以下のように3つの異なる方法を提供した.
方法:
ケース:
まとめ
この文章の中で、私達はThreadのいくつかの比較的によくあるAPIを学んで、ThreadのAPIは高い同時プログラミングの基礎を掌握するので、とても熟練して掌握する必要があります!
今日の文章はここまで终わって、友达はどんな提案あるいは意见があって私に连络して改善してください、あなた达の支持は私の最大の动力です!!!
本文はブロググループから1文多発などの運営ツールプラットフォームを配布する.
OpenWriteリリース
Threadクラスが提供するAPIは数十個あり,紙面の問題のため,本論文では代表的なものをいくつか選択して説明する.残りのAPIの仲間たちが興味を持っているのはソースコードで調べることができて、私に伝言を与えることができて、私たちは共同で勉強することを検討します.
ターゲット
内容
1. currentThread
この方法は、現在の実行スレッドの参照を返すために使用され、コードブロックで現在のスレッドオブジェクトを取得することができます.簡単に見えますが、非常に広く使用されており、後続のコンテンツで多く使用されます.
方法:
public static native Thread currentThread();
コード:
/**
* Thread.currentThread() 。
*/
public class CurrentThreadDemo {
public static void main(String[] args) {
// :true
Thread t = new Thread(() -> {
System.out.println("t".equals(Thread.currentThread().getName()));
}, "t");
t.start();
// :true
System.out.println("main".equals(Thread.currentThread().getName()));
}
}
2. setPriority
プロセスにはプロセスの優先度があり,スレッドにも優先度があり,理論的には優先度の高いスレッドはCPUによって優先的にスケジューリングされるが,実際には望ましくないことが多い.
CPUが忙しい場合、優先度を設定するとより多くのCPUタイムスライスが得られる可能性がありますが、CPUが空いている場合、優先度を設定することはほとんど役に立ちません.したがって、プログラム設計で優先度を使用して特定のビジネスをバインドしたり、ビジネスを優先度に依存させたりしようとしないでください.この結果は、あなたが望む結果と一致しない可能性があります.
方法:
public final void setPriority(int newPriority); //
public final int getPriority(); //
ケース:
/**
* t1 t2 , t2
* :
* t1: 59573
* t2: 34321
* CPU ,
*/
public class PriorityDemo {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
while (true) {
System.out.println("t1");
}
}, "t1");
Thread t2 = new Thread(() -> {
while (true) {
System.out.println("t2");
}
}, "t2");
// :1, :5, :10
t1.setPriority(9);
t2.setPriority(10);
t1.start();
t2.start();
}
}
3. yield
yieldメソッドは、スケジューラに現在のスレッドがプロセッサの現在の使用を放棄することを示す啓発的なメソッドに属します.スケジューラは、このプロンプトを無視できます.詳細なパフォーマンス分析とベンチマークテストと組み合わせて、実際に必要な効果があることを確認する必要があります.
この方法はあまり使われていません.デバッグまたはテストの目的では、競合条件によるエラーの再現に役立つ可能性があります.
方法:
public static native void yield();
ケース:
/**
* 0 , 1
* , 0
*/
public class YieldDemo {
public static void main(String[] args) {
IntStream.range(0, 2).mapToObj(YieldDemo::test).forEach(Thread::start);
}
private static Thread test(int index){
return new Thread(() -> {
// if (index == 0){
// Thread.yield();
// }
System.out.println(index);
});
}
}
4. sleep
sleepは、システムタイマとスケジューラの精度と正確性に基づいて、現在実行中のスレッドを指定したミリ秒数までスリープ状態(一時的に実行を停止)にします.このスレッドはモニタの所有権を失うことはありません(例えばmonitorロック、monitorロックについては後述します).
方法:
public static native void sleep(long millis); //
public static void sleep(long millis, int nanos); //
ケース:
/**
* , ,
* Thread.sleep()
*/
public class SleepDemo {
public static void main(String[] args) {
new Thread(() -> {
long startTime = System.currentTimeMillis();
sleep(2000);
System.out.printf("%s :%d%s", Thread.currentThread().getName(), System.currentTimeMillis() - startTime, "ms");
System.out.println("");
}, "t").start();
long startTime = System.currentTimeMillis();
sleep(3000);
System.out.printf("%s :%d%s", Thread.currentThread().getName(), System.currentTimeMillis() - startTime, "ms");
}
private static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
yieldとsleepの違い:
5. interrupt
スレッドinterruptは非常に重要なAPIであり、呼び出された場合、よく使用される方法でもあります.
InterruptedException
が受信される.java.nio.channels.ClosedByInterruptException
を受け取る.これに関連するAPIはまだいくつかあります.
方法:
public void interrupt(); //
public static boolean interrupted(); // ,
public boolean isInterrupted(); // ,
// interrupted isInterrupted isInterrupted() , ClearInterrupted interrupt , , false
private native boolean isInterrupted(boolean ClearInterrupted);
ケース:
/**
* t, 1
* 2 , t , :interrupt,
*/
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
try {
Thread.sleep(60 * 1000);
} catch (InterruptedException e) {
System.out.println("interrupt");
}
}, "t");
t.start();
Thread.sleep(2000);
t.interrupt();
}
}
スレッドの内部には
interrupt flag
という識別子が存在し、スレッドがinterrupt
である場合、そのflag
が設定され、ソースコードにも対応する記述が見られる.public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
しかし、現在のスレッドが割り込み可能なメソッドを実行している場合、
interrupt
メソッドを呼び出して割り込み、逆にflag
が明らかになることは、後述する.7. join
Threadのjoin法も同様に非常に重要な方法であり,その特性を用いて多くの比較的強い機能を実現することができ,Threadクラスでは以下のように3つの異なる方法を提供した.
方法:
public final void join(); //
public final synchronized void join(long millis); // , 0
public final synchronized void join(long millis, int nanos); // , 0
ケース:
/**
* 1 2 , 。
* main , 1 2
* main , join ,
*/
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
List list = IntStream.range(1, 3).mapToObj(JoinDemo::getThread).collect(Collectors.toList());
list.forEach(Thread::start);
for (Thread thread : list) {
thread.join();
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "-" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static Thread getThread(int name){
return new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "-" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, String.valueOf(name));
}
}
まとめ
この文章の中で、私達はThreadのいくつかの比較的によくあるAPIを学んで、ThreadのAPIは高い同時プログラミングの基礎を掌握するので、とても熟練して掌握する必要があります!
今日の文章はここまで终わって、友达はどんな提案あるいは意见があって私に连络して改善してください、あなた达の支持は私の最大の动力です!!!
本文はブロググループから1文多発などの運営ツールプラットフォームを配布する.
OpenWriteリリース