synchronizedキーワード理解

6310 ワード

javaにおけるsynchronizedの使い方
       synchronizedキーを使って、マルチスレッド共有データ同期問題を簡単に解決できます。
 synchronizedキーワードは、関数の修飾子としてもよく、関数内のステートメントとしてもよく、つまり、通常の同期方法と同期ステートメントブロックとしてもよい。さらに細かい分類があれば、instance変数、object reference(オブジェクト参照)、static関数、class literals(クラス名字面常量)に役立ちます。 
       synchronizedが取得したロックはすべて対象です。各オブジェクトは一つのロックだけが関連しています。同期を実現するには大きなシステムオーバーヘッドが代償となり、デッドロックを引き起こす可能性もあるので、無駄な同期制御はできるだけ避けます。
 
synchronizedの4つの使い方
1.      メソッド宣言時に使用して、スレッドが取得されたのはメンバーロックです。
2.      あるコードブロックに対して、synchronizedのかかと括弧、括弧の中で変数で、スレッドはメンバーロックを獲得します。
3.  synchronizedの後ろの括弧の中で一つのオブジェクトがあります。この時、スレッドは対象のロックを獲得します。
4.  synchronizedの後ろの括弧にはクラスがあり、この時スレッドが獲得されるのはオブジェクトロックです。 
java筆記三——synchronizedいくつかの例
本文はCSDNブログから来ました。転載は出所を明記してください。http://blog.csdn.net/alex197963/archive/2009/08/06/4417414.aspx 一つは、同じ対象のobjectのこのsynchronized同期コードブロックに二つのスレッドが同時にアクセスする場合、一つのスレッドだけが実行されます。もう一つのスレッドは、現在のスレッドがこのコードブロックを実行するのを待つ必要があります。
二、しかし、一方のスレッドがObjectの1つのsynchronized同期コードブロックにアクセスすると、他のスレッドはこのObjectの非synchronized同期コードブロックにまだアクセスすることができる。
特に、スレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、他のスレッドがobjectの中の他のすべてのsynchronized(this)同期コードブロックに対するアクセスが遮断されます。
四、第三の例は、他の同期コードブロックにも適用される。つまり、スレッドがobjectのsynchronized同期コードブロックにアクセスすると、このobjectのオブジェクトロックが得られる。その結果、他のスレッドはこのOBプロジェクトオブジェクトの同期コードのすべての部分へのアクセスを一時的に停止した。
五、以上の規則は他のオブジェクトのロックにも適用されます。
例を挙げて説明します
一つは、同じ対象のobjectのこのsynchronized同期コードブロックに二つのスレッドが同時にアクセスする場合、一つのスレッドだけが実行されます。もう一つのスレッドは、現在のスレッドがこのコードブロックを実行するのを待つ必要があります。
package ths;
public class Thread1 implements Runnable {
public void run() {
synchronized(this) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
}
}
}
public static void main(String[] args) {
Thread1 t1 = new Thread1();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t1, "B");
ta.start();
tb.start();
}
}
結果:
A synchronized loop 0
A synchronized loop 1
A synchronized loop 2
A synchronized loop 3
A synchronized loop 4
B synchronized loop 0
B synchronized loop 1
B synchronized loop 2
B synchronized loop 3
B synchronized loop 4
二、しかし、一方のスレッドがObjectの1つのsynchronized同期コードブロックにアクセスすると、他のスレッドはこのObjectの非synchronized同期コードブロックにまだアクセスすることができる。
package ths;
public class Thread2 {
public void m4t1() {
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
}
public void m4t2() {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
public static void main(String[] args) {
final Thread2 myt2 = new Thread2();
Thread t1 = new Thread(
new Runnable() {
public void run() {
myt2.m4t1();
}
}, "t1"
);
Thread t2 = new Thread(
new Runnable() {
public void run() {
myt2.m4t2();
}
}, "t2"
);
t1.start();
t2.start();
}
}
結果:
t1 : 4
t2 : 4
t1 : 3
t2 : 3
t1 : 2
t2 : 2
t1 : 1
t2 : 1
t1 : 0
t2 : 0
特に、スレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、他のスレッドがobjectの中の他のすべてのsynchronized(this)同期コードブロックに対するアクセスが遮断されます。
//  Thread2.m4t2()  :
public void m4t2() {
synchronized(this) {
int i = 5;
while( i-- > 0) {


System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
}
結果:
t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
t2 : 4
t2 : 3
t2 : 2
t2 : 1
t2 : 0
四、第三の例は、他の同期コードブロックにも適用される。つまり、スレッドがobjectのsynchronized同期コードブロックにアクセスすると、このobjectのオブジェクトロックが得られる。その結果、他のスレッドはこのOBプロジェクトオブジェクトの同期コードのすべての部分へのアクセスを一時的に停止した。
//  Thread2.m4t2()    :
public synchronized void m4t2() {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
結果:
t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
t2 : 4
t2 : 3
t2 : 2
t2 : 1
t2 : 0
五、以上の規則は他のオブジェクトのロックにも適用されます。
package ths;
public class Thread3 {
class Inner {
private void m4t1() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}
private void m4t2() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}
}
private void m4t1(Inner inner) {
synchronized(inner) { //     
inner.m4t1();
}
}
private void m4t2(Inner inner) {
inner.m4t2();
}
public static void main(String[] args) {
final Thread3 myt3 = new Thread3();
final Inner inner = myt3.new Inner();
Thread t1 = new Thread(
new Runnable() {
public void run() {
myt3.m4t1(inner);
}
}, "t1"
);
Thread t2 = new Thread(
new Runnable() {
public void run() {
myt3.m4t2(inner);
}
}, "t2"
);
t1.start();
t2.start();
}
}
結果:
スレッドt 1はInnerに対するオブジェクトロックを取得しているが、スレッドt 2は同じInnerの中の非同期部分にアクセスしているためである。だから二つのスレッドは互いに干渉しない。
t1 : Inner.m4t1()=4
t2 : Inner.m4t2()=4
t1 : Inner.m4t1()=3
t2 : Inner.m4t2()=3
t1 : Inner.m4t1()=2
t2 : Inner.m4t2()=2
t1 : Inner.m4t1()=1
t2 : Inner.m4t2()=1
t1 : Inner.m4t1()=0
t2 : Inner.m4t2()=0
現在はInner.m 4 t 2()の前にsynchronizedを追加します。
private synchronized void m4t2() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}
結果:
スレッドt 1は、t 2と同じInnerオブジェクトの中の2つの無関係な部分にアクセスしたが、t 1は最初にInnerのオブジェクトロックを獲得したので、t 2のInner.m 4 t 2()へのアクセスもブロックされている。m 4 t 2()はInnerの同期方法の一つである。
t1 : Inner.m4t1()=4
t1 : Inner.m4t1()=3
t1 : Inner.m4t1()=2
t1 : Inner.m4t1()=1
t1 : Inner.m4t1()=0
t2 : Inner.m4t2()=4
t2 : Inner.m4t2()=3
t2 : Inner.m4t2()=2
t2 : Inner.m4t2()=1
t2 : Inner.m4t2()=0
from:http://www.cnblogs.com/TankMa/archive/2011/08/03/2125997.html