JAVAスレッド03:synchronizedキーワード
3177 ワード
スレッド同期の問題を示し、2つのスレッドを作成し、同じオブジェクトの出力方法を実行します.
実行結果:
明らかに出力された文字列が乱され、私たちが期待している出力結果はaaaabbbbbであり、これがスレッド同期の問題であり、outputメソッドが1つのスレッドで完全に実行された後、次のスレッドに切り替えることを望んでいる.Javaではロックメカニズムを使用して、マルチスレッド実行時にコードが反発することを保証します.
一、内蔵ロック:synchronizedキーワード.
Javaでsynchronizedを使用すると、マルチスレッド実行時にコードが反発することを保証します.2つの方法があります.
1. synchronizedを使用して、反発が必要なコードを含め、ロックをかけます.
このロックは、反発が必要な複数のスレッド間の共有オブジェクトでなければなりません.次のコードのように意味がありません.
このコードブロックに入るたびに新しいobjが作成され、このロックは明らかに各スレッドが作成され、意味がありません.
2. synchronizedを反発が必要な方法に追加します.
この方式はthisでメソッド全体をロックするコードブロックに相当し,synchronizedで静的メソッドに加算すると,××××.classはメソッド全体のコードブロックをロックします.synchronizedを使用すると、場合によってはデッドロックになります.synchronized修飾を用いた方法またはコードブロックは、原子操作と見なすことができる.
各ロックには2つのキューがあり、1つは準備キュー、1つはブロックキューであり、準備キューはロックを取得するスレッドを格納し、ブロックキューはブロックされたスレッドを格納し、1つのスレッドが起動されると、準備キューに入り、CPUのスケジューリングを待つ.逆に、1つのスレッドがwaitされると、ブロックキューに入り、次の起動を待つ.これはスレッド間のパスに関連する.我々の例を見ると、第1のスレッドが出力メソッドを実行すると、同期ロックが得られ、出力メソッドが実行され、ちょうどこのとき第2のスレッドも出力メソッドを実行するが、同期ロックが解放されていないことが判明し、第2のスレッドは準備キューに入り、ロックが解放されるのを待つ.1つのスレッドが反発コードを実行する手順は、次のとおりです.
1. 同期ロックを取得します.
2. ワークメモリを空にします.
3. メインメモリからオブジェクトのコピーをワークメモリにコピーします.
4. 実行コード(計算や出力など);
5. メインメモリデータをリフレッシュします.
6. 同期ロックを解除します.
したがってsynchronizedは、マルチスレッドの同時秩序性を保証するとともに、マルチスレッドのメモリ可視性を保証する.
public class PrintChar {
public void output(String name) {
try {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
Thread.sleep(1);
}
} catch (InterruptedException e) {
}
}
}
public static void main(String[] args) {
final PrintChar printer = new PrintChar();
new Thread() {
public void run() {
printer.output("aaaaa");
};
}.start();
new Thread() {
public void run() {
printer.output("bbbbb");
};
}.start();
}
実行結果:
abababbaba
明らかに出力された文字列が乱され、私たちが期待している出力結果はaaaabbbbbであり、これがスレッド同期の問題であり、outputメソッドが1つのスレッドで完全に実行された後、次のスレッドに切り替えることを望んでいる.Javaではロックメカニズムを使用して、マルチスレッド実行時にコードが反発することを保証します.
一、内蔵ロック:synchronizedキーワード.
Javaでsynchronizedを使用すると、マルチスレッド実行時にコードが反発することを保証します.2つの方法があります.
1. synchronizedを使用して、反発が必要なコードを含め、ロックをかけます.
public class PrintChar {
public void output(String name) {
try {
synchronized (this) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
Thread.sleep(1);
}
}
} catch (InterruptedException e) {
}
}
}
このロックは、反発が必要な複数のスレッド間の共有オブジェクトでなければなりません.次のコードのように意味がありません.
public class PrintChar {
public void output(String name) {
try {
Object obj = new Object();
synchronized (obj) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
Thread.sleep(1);
}
}
} catch (InterruptedException e) {
}
}
}
このコードブロックに入るたびに新しいobjが作成され、このロックは明らかに各スレッドが作成され、意味がありません.
2. synchronizedを反発が必要な方法に追加します.
public class PrintChar {
public synchronized void output(String name) {
try {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
Thread.sleep(1);
}
} catch (InterruptedException e) {
}
}
}
この方式はthisでメソッド全体をロックするコードブロックに相当し,synchronizedで静的メソッドに加算すると,××××.classはメソッド全体のコードブロックをロックします.synchronizedを使用すると、場合によってはデッドロックになります.synchronized修飾を用いた方法またはコードブロックは、原子操作と見なすことができる.
各ロックには2つのキューがあり、1つは準備キュー、1つはブロックキューであり、準備キューはロックを取得するスレッドを格納し、ブロックキューはブロックされたスレッドを格納し、1つのスレッドが起動されると、準備キューに入り、CPUのスケジューリングを待つ.逆に、1つのスレッドがwaitされると、ブロックキューに入り、次の起動を待つ.これはスレッド間のパスに関連する.我々の例を見ると、第1のスレッドが出力メソッドを実行すると、同期ロックが得られ、出力メソッドが実行され、ちょうどこのとき第2のスレッドも出力メソッドを実行するが、同期ロックが解放されていないことが判明し、第2のスレッドは準備キューに入り、ロックが解放されるのを待つ.1つのスレッドが反発コードを実行する手順は、次のとおりです.
1. 同期ロックを取得します.
2. ワークメモリを空にします.
3. メインメモリからオブジェクトのコピーをワークメモリにコピーします.
4. 実行コード(計算や出力など);
5. メインメモリデータをリフレッシュします.
6. 同期ロックを解除します.
したがってsynchronizedは、マルチスレッドの同時秩序性を保証するとともに、マルチスレッドのメモリ可視性を保証する.