最初の2つのセクションでは- 「マルチスレッドの基礎Javaのマルチスレッド(a)の学習」と「Javaのマルチスレッド学習(2) -導入のThreadクラスのメソッドを」我々は、スレッドセーフ-と非スレッドセーフの考え方に連絡しましたセクションでは、synchronizedキーワードの使用について学ぶ必要があります。
1、スレッドの安全性の変数
この方法は、プライベート変数、内部にある場合は、「非スレッドセーフ」の問題は、「インスタンス変数」に存在する「非スレッドセーフ、」問題は存在しません。2つのスレッドが同時にオブジェクトのインスタンス変数を操作する場合は、非スレッドセーフの問題があるだろう、解決策は、この方法で同期synchronizedキーワードを追加してコントロールを追加することです。
図2に示すように、ロック複数のオブジェクトの複数
コードを見てください:
public class HasSelfPrivateNum {
// 创建被同步关键字修饰的方法
private int num = 0;
synchronized public void add(String name){
try {
if ("a".equals(name)){
num = 100;
System.out.println("a set over");
Thread.sleep(2000);
}else {
num = 200;
System.out.println("b set over");
}
System.out.println(name + " num = " + num);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public class ThreadA extends Thread {
// 创建线程,构造器传参为上面方法的对象
private HasSelfPrivateNum hasSelfPrivateNum;
public ThreadA(String name, HasSelfPrivateNum hasSelfPrivateNum){
super();
this.hasSelfPrivateNum = hasSelfPrivateNum;
this.setName(name);
}
@Override
public void run() {
super.run();
hasSelfPrivateNum.add(this.getName());
}
}
// main方法和输出
public static void main(String[] args){
HasSelfPrivateNum hasSelfPrivateNum = new HasSelfPrivateNum();
HasSelfPrivateNum hasSelfPrivateNum1 = new HasSelfPrivateNum();
ThreadA threadA = new ThreadA("a", hasSelfPrivateNum);
ThreadA threadA1 = new ThreadA("b", hasSelfPrivateNum1);
threadA.start();
threadA1.start();
}
b set over
a set over
b num = 200
a num = 100
この例としては、それは2つのロックを持っていますので、2つのHasSelfPrivateNumオブジェクトを作成し、その結果が非同期で実行されています。
ロックはなくコードまたは方法のロック片としてよりも、オブジェクトのロックを取得するために同期されます。複数のスレッドが同じにアクセスするのであれば、上記の例では、スレッドの最初の実装は、synchronizedキーワードでロック方法をロックし、この方法は、オブジェクトに属して保持しているスレッドは、その後、他のスレッドが唯一の状態で待機することができますオブジェクト。複数のスレッドが複数のオブジェクトにアクセスする場合は、JVMは、複数のロックを作成します。
主方向は少し変更されました:
public static void main(String[] args){
HasSelfPrivateNum hasSelfPrivateNum = new HasSelfPrivateNum();
//HasSelfPrivateNum hasSelfPrivateNum1 = new HasSelfPrivateNum();
ThreadA threadA = new ThreadA("a", hasSelfPrivateNum);
ThreadA threadA1 = new ThreadA("b", hasSelfPrivateNum);
threadA.start();
threadA1.start();
}
----
a set over
a num = 100
b set over
b num = 200
そして、スレッドA threadA1は、オブジェクトのロックを取得見ることができ、それは、出力の順序です。
図3に示すように、オブジェクトのメソッドと同期
以上により、我々は、オブジェクトが同期ロックがなくコードまたはロック方法の一部としてよりも、取得されたロックことを知っています。複数のスレッドがsynchronizedキーワードでメソッドを実行するためのスレッド同じオブジェクトにアクセスする場合、このメソッドを保持しているスレッドは、他のスレッドは待機状態にすることができます。複数のスレッドがオブジェクトにアクセスする場合は、複数のオブジェクトが複数のロックを持っていますので、必ずしも以上ではありません。
複数のスレッドが同期キーワードが修正された方法、スレッドの非同期呼び出し未修飾方法において同じオブジェクトでないアクセスする場合。
4、ダーティリード
割り当てが同時に行われる場合にはこの場合の値はそのダーティリードする場合、いくつかの予期せぬサプライズがあるかもしれません。ダーティ・リードの場合は、インスタンス変数を読んで発生し、この値が別のスレッドによって変更されています。
public class DirtyReadTest {
// 创建同步修改数据方法,非同步取数据方法
public String username = "A";
public String password = "AA";
synchronized public void setValue(String username, String password){
try {
this.username = username;
Thread.sleep(5000);
this.password = password;
System.out.println("setValue method: username = " + username + " password = " + password);
}catch (InterruptedException e){
e.printStackTrace();
}
}
public void getValue(){
System.out.println("getValue method: username = " + username + " password = " + password);
}
}
public class ThreadTest extends Thread {
private DirtyReadTest dirtyReadTest;
public ThreadTest(DirtyReadTest dirtyReadTest){
super();
this.dirtyReadTest=dirtyReadTest;
}
@Override
public void run() {
super.run();
dirtyReadTest.setValue("B", "BB");
}
}
出力:
public static void main(String[] args) throws Exception{
DirtyReadTest dirtyReadTest = new DirtyReadTest();
ThreadTest threadTest = new ThreadTest(dirtyReadTest);
threadTest.start();
Thread.sleep(200);
dirtyReadTest.getValue();
}
getValue method: username = B password = AA
setValue method: username = B password = BB
ソリューションは、getValueメソッドにsynchronizedキーワードを追加することです。
場合同期方法スレッド1つのコールオブジェクトA、スレッド1、スレッド2である、オブジェクトのロックを取得する取得できないオブジェクトのメソッドが同期化されているのいずれかが修飾が、同期修正方法がアクセスすることができません。
5、同期ロックリエントラント
スレッドがオブジェクトのロックを取得した場合、同期の使用では、再び要求されたオブジェクトのロックを再取得することができ、解放されません。リエントラントでないロックはデッドロックを引き起こす可能性があれば、オブジェクトのメソッドの同期の変更は、他の方法で変更同期されたオブジェクトにアクセスすることができます。
試験方法:
public class Service {
synchronized public void service1(){
System.out.println("service1");
service2();
}
synchronized public void service2(){
System.out.println("service2");
service3();
}
synchronized public void service3(){
System.out.println("service3");
}
}
public class ThreadTest extends Thread {
@Override
public void run() {
super.run();
Service service = new Service();
service.service1();
}
}
public static void main(String[] args){
ThreadTest threadTest = new ThreadTest();
threadTest.start();
}
service1
service2
service3
リエントラントロックはまた、親子クラスでサポートされている環境を継承し、サブクラスはリエントラントロックを介して呼び出さ親クラスを同期させることができます。これはもはや書くコードではありません、あなたは自己書かを書くことができます。
図6に示すように、異常な、自動解除
スレッドの例外コードの実行が発生した場合、すべてのロックが自動的に解除されます。
7、同期は継承を持っていません
親クラスが同期されたキーワードを持つメソッドを持っている場合は、サブクラスが継承し、このメソッドをオーバーライドします。しかし、同期は彼らはまだ、サブクラスのメソッドにsynchronizedキーワードを追加する必要があり、継承することはできません。
コードのこのセクションではGitHubの。
国民の関心番号へようこそ。