この章では、同期されたキーワードを紹介します。関係するコンテンツには以下が含まれます。
1。同期された原理
2。同期された基本ルール
3。同期されたメソッドと同期コードブロック
4.インスタンスロックとグローバルロック
1。同期された原理
Javaでは、各オブジェクトには1つの同期ロックのみがあります。これはまた、同期ロックがオブジェクトに存在することを意味します。
オブジェクトの同期メソッドを呼び出すと、オブジェクトの同期ロックを取得します。たとえば、同期(OBJ)は、「OBJオブジェクト」の同期ロックを取得します。
異なるスレッドによる同期ロックへのアクセスは相互に排他的です。言い換えれば、特定の時点で、オブジェクトの同期ロックは1つのスレッドでのみ取得できます!同期ロックを介して、複数のスレッドで「オブジェクト/メソッド」への相互に排他的なアクセスを実現できます。 たとえば、2つのスレッドAとスレッドBがあり、どちらも「オブジェクトOBJの同期ロック」にアクセスします。ある時点で、「OBJの同期ロック」を取得し、この時点で「OBJの同期ロック」を取得しようとすると、スレッドBは取得できません。 bは、「このオブジェクトの同期ロック」が解放され、実行できるようになるまで、「OBJの同期ロック」のみを取得できます。
2。同期された基本ルール
次の3つに同期した基本的なルールを要約し、例を通してそれらを説明します。
第1条:スレッドが「同期されたメソッド」または「特定のオブジェクト」の「同期コードブロック」にアクセスすると、他のスレッドは「オブジェクト」の「同期メソッド」または「同期コードブロック」へのアクセスからブロックされます。
第2条:スレッドが「特定のオブジェクト」の「同期メソッド」または「同期コードブロック」にアクセスすると、他のスレッドは「このオブジェクト」の非同期コードブロックにアクセスできます。
第3条:「特定のオブジェクト」の「同期メソッド」または「同期コードブロック」にアクセスすると、「オブジェクト」の他の「同期メソッド」または「同期コードブロック」にアクセスすることができます。
第1条
スレッドが「特定のオブジェクト」の「同期メソッド」または「同期コードブロック」にアクセスすると、他のスレッドは「オブジェクト」の「同期メソッド」または「同期コードブロック」へのアクセスからブロックされます。
以下は、「同期コードブロック」に対応するデモプログラムです。
コードコピーは次のとおりです。
クラスmyrunableは実行可能{
@オーバーライド
public void run(){
同期(This){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname() + "loop" + i);
}
} catch(arternedexception ie){
}
}
}
}
パブリッククラスdemo1_1 {
public static void main(string [] args){
runnable demo = new myRunable();
スレッドT1 =新しいスレッド(デモ、 "T1");
スレッドT2 =新しいスレッド(デモ、 "T2");
t1.start();
t2.start(); //「スレッドT2」を開始します
}
}
実行結果:
コードコピーは次のとおりです。
T1ループ0
T1ループ1
T1ループ2
T1ループ3
T1ループ4
T2ループ0
T2ループ1
T2ループ2
T2ループ3
T2ループ4
結果説明:
run()メソッドには「同期(この)コードブロック」があり、T1とT2は「デモ」実行可能なオブジェクトに基づいて作成されたスレッドです。これは、これを「デモ実行可能なオブジェクト」と同期していることを意味します。したがって、T1とT2は「デモオブジェクトの同期ロック」を共有します。したがって、1つのスレッドが実行されている場合、別のスレッドが「ランニングスレッド」が実行される前に「デモ同期ロック」をリリースするのを待つ必要があります。
確認した場合、この問題を見つけました。次に、上記のコードを変更してから、結果がどのようになっているかを確認し、混乱するかどうかを確認します。変更されたソースコードは次のとおりです。
コードコピーは次のとおりです。
クラスmythreadはスレッドを拡張します{
public mythread(string name){
super(name);
}
@オーバーライド
public void run(){
同期(This){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname() + "loop" + i);
}
} catch(arternedexception ie){
}
}
}
}
パブリッククラスdemo1_2 {
public static void main(string [] args){
スレッドT1 = new Mythread( "T1");
スレッドT2 = new Mythread( "T2");
t1.start();
t2.start(); //「スレッドT2」を開始します
}
}
コード説明:
Demo1_2とDemo1_1を比較すると、Demo1_2のMythreadクラスはスレッドから直接継承され、T1とT2は両方ともMythRead Childスレッドであることがわかりました。
幸いなことに、「demo1_2のrun()メソッド」は、同期(this)とも呼ばれます。
Demo1_2の実行プロセスはDemo1_1と同じですか?
実行結果:
コードコピーは次のとおりです。
T1ループ0
T2ループ0
T1ループ1
T2ループ1
T1ループ2
T2ループ2
T1ループ3
T2ループ3
T1ループ4
T2ループ4
結果説明:
この結果がまったく驚かないなら、私はあなたが同期とこれをより深く理解していると信じています。それ以外の場合は、ここで分析を読み続けてください。
これは、同期された(これ)、「現在のクラスオブジェクト」、つまり同期(この)が配置されているクラスに対応する現在のオブジェクトを指します。その目的は、「現在のオブジェクトの同期ロック」を取得することです。
Demo1_2の場合、これは同期(This)はMythreadオブジェクトを表し、T1とT2は2つの異なるMythreadオブジェクトです。 DEMO1_1ペアの場合、これはMyRunableオブジェクトを表します。
第2条
スレッドが「特定のオブジェクト」の「同期メソッド」または「同期コードブロック」にアクセスすると、他のスレッドは「このオブジェクト」の非同期コードブロックにアクセスできます。
以下は、「同期コードブロック」に対応するデモプログラムです。
コードコピーは次のとおりです。
クラスカウント{
//同期化された同期ブロックを含むメソッド
public void synmethod(){
同期(This){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getName() + "Synmethod loop" + i);
}
} catch(arternedexception ie){
}
}
}
//非同期メソッド
public void nonsynmethod(){
試す {
for(int i = 0; i <5; i ++){
thread.sleep(100);
system.out.println(thread.currentthread()。getName() + "nonsynmethod loop" + i);
}
} catch(arternedexception ie){
}
}
}
パブリッククラスDemo2 {
public static void main(string [] args){
最終count count = new count();
//新しいT1を作成すると、T1は「カウントオブジェクト」のsynmethod()メソッドを呼び出します
スレッドT1 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
count.synmethod();
}
}、 "t1");
//新しいT2を作成し、T2は「カウントオブジェクト」のnonsynmethod()メソッドを呼び出します
スレッドT2 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
count.nonsynmethod();
}
}、 "t2");
t1.start();
t2.start();
}
}
実行結果:
コードコピーは次のとおりです。
T1同期ループ0
T2 Nonsynmethodループ0
T1同期ループ1
T2 Nonsynmethodループ1
T1同期ループ2
T2 Nonsynmethod Loop 2
T1同期ループ3
T2 Nonsynmethodループ3
T1同期ループ4
T2 Nonsynmethod Loop 4
結果説明:
2つの新しい子スレッドT1とT2がメインスレッドに作成されます。 T1は、同期オブジェクトの同期ブロックを含むカウントオブジェクトのsynmethod()メソッドを呼び出します。 T1が実行されている場合、「カウント同期ロック」を取得するために同期されますが、T2は「カウント」同期ロックを使用しないためにブロックされません。
第3条
スレッドが「特定のオブジェクト」の「同期メソッド」または「同期コードブロック」にアクセスすると、「オブジェクト」の他の「同期メソッド」または「同期コードブロック」への他のスレッドアクセスがブロックされます。
また、上記の例では、同期(これ)を使用して、上記の例でnonsynmethod()メソッド本体を変更します。変更されたソースコードは次のとおりです。
コードコピーは次のとおりです。
クラスカウント{
//同期化された同期ブロックを含むメソッド
public void synmethod(){
同期(This){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getName() + "Synmethod loop" + i);
}
} catch(arternedexception ie){
}
}
}
//同期同期ブロックメソッドも含まれています
public void nonsynmethod(){
同期(This){
試す {
for(int i = 0; i <5; i ++){
thread.sleep(100);
system.out.println(thread.currentthread()。getName() + "nonsynmethod loop" + i);
}
} catch(arternedexception ie){
}
}
}
}
パブリッククラスDemo3 {
public static void main(string [] args){
最終count count = new count();
//新しいT1を作成すると、T1は「カウントオブジェクト」のsynmethod()メソッドを呼び出します
スレッドT1 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
count.synmethod();
}
}、 "t1");
//新しいT2を作成し、T2は「カウントオブジェクト」のnonsynmethod()メソッドを呼び出します
スレッドT2 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
count.nonsynmethod();
}
}、 "t2");
t1.start();
t2.start();
}
}
(一度)実行結果:
コードコピーは次のとおりです。
Synmethod():11
Synblock():3
4.インスタンスロックとグローバルロック
インスタンスロック - インスタンスオブジェクトにロックされています。クラスがシングルトンの場合、ロックにはグローバルロックの概念もあります。
同期されたキーワードは、インスタンスロックに対応します。
グローバルロック - このロックは、インスタンスがいくつのオブジェクトであっても、ロックを共有しています。
グローバルロックは、静的同期に対応しています(またはこのクラスのクラスまたはクラスローダーオブジェクトにロックされています)。
「インスタンスロック」と「グローバルロック」の非常に鮮明な例があります。
コードコピーは次のとおりです。
パルビッククラス何か{
public同期されたvoid issynca(){}
public同期void issyncb(){}
public static同期void csynca(){}
public static同期void csyncb(){}
}
と仮定すると、何かに2つのインスタンスxとyがあります。次の4セットの式で取得されたロックを分析します。
(01)x.issynca()およびx.issyncb()
(02)x.issynca()およびy.issynca()
(03)x.csynca()およびy.csyncb()
(04)x.issynca()およびsoments.csynca()
(01)同時にアクセスできません。 Issynca()とIssyncb()は両方とも同じオブジェクトにアクセスする同期ロックであるためです(オブジェクトX)!
コードコピーは次のとおりです。
// locktest2.javaソースコード
何かをクラスする{
public同期されたvoid issynca(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":issynca");
}
} catch(arternedexception ie){
}
}
public同期void issyncb(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":issyncb");
}
} catch(arternedexception ie){
}
}
public static同期void csynca(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":csynca");
}
} catch(arternedexception ie){
}
}
public static同期void csyncb(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":csyncb");
}
} catch(arternedexception ie){
}
}
}
パブリッククラスLockTest2 {
何かx =新しい何か();
何かy = new何か();
//(02)x.issynca()とy.issynca()を比較します
private void test2(){
//新しいT21を作成すると、T21はx.issynca()を呼び出します
スレッドT21 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
x.issynca();
}
}、 "t21");
//新しいT22を作成すると、T22はx.issyncb()を呼び出します
スレッドT22 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
y.issynca();
}
}、 "t22");
t21.start();
t22.start();
}
public static void main(string [] args){
locktest2 demo = new LockTest2();
demo.test2();
}
}
実行結果:
コードコピーは次のとおりです。
T11:Issynca
T11:Issynca
T11:Issynca
T11:Issynca
T11:Issynca
T12:Issyncb
T12:Issyncb
T12:Issyncb
T12:Issyncb
T12:Issyncb
(02)同時にアクセスできます。同じオブジェクトの同期ロックにアクセスしていないため、x.issynca()はxの同期ロックにアクセスし、y.issynca()はyの同期ロックにアクセスします。
コードコピーは次のとおりです。
// locktest2.javaソースコード
何かをクラスする{
public同期されたvoid issynca(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":issynca");
}
} catch(arternedexception ie){
}
}
public同期void issyncb(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":issyncb");
}
} catch(arternedexception ie){
}
}
public static同期void csynca(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":csynca");
}
} catch(arternedexception ie){
}
}
public static同期void csyncb(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":csyncb");
}
} catch(arternedexception ie){
}
}
}
パブリッククラスLockTest2 {
何かx =新しい何か();
何かy = new何か();
//(02)x.issynca()とy.issynca()を比較します
private void test2(){
//新しいT21を作成すると、T21はx.issynca()を呼び出します
スレッドT21 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
x.issynca();
}
}、 "t21");
//新しいT22を作成すると、T22はx.issyncb()を呼び出します
スレッドT22 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
y.issynca();
}
}、 "t22");
t21.start();
t22.start();
}
public static void main(string [] args){
locktest2 demo = new LockTest2();
demo.test2();
}
}
実行結果:
コードコピーは次のとおりです。
T21:Issynca
T22:Issynca
T21:Issynca
T22:Issynca
T21:Issynca
T22:Issynca
T21:Issynca
T22:Issynca
T21:Issynca
T22:Issynca
(03)同時にアクセスできません。 csynca()とcsyncb()はどちらも静的タイプであるため、x.csynca()はsoments.issynca()と同等であり、y.csyncb()はsoments.issyncb()と同等であるため、同期ロックを共有し、同時に尋ねられます。
コードコピーは次のとおりです。
// locktest3.javaソースコード
何かをクラスする{
public同期されたvoid issynca(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":issynca");
}
} catch(arternedexception ie){
}
}
public同期void issyncb(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":issyncb");
}
} catch(arternedexception ie){
}
}
public static同期void csynca(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":csynca");
}
} catch(arternedexception ie){
}
}
public static同期void csyncb(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":csyncb");
}
} catch(arternedexception ie){
}
}
}
パブリッククラスLockTest3 {
何かx =新しい何か();
何かy = new何か();
//(03)x.csynca()とy.csyncb()を比較します
private void test3(){
//新しいT31を作成すると、T31はx.issynca()を呼び出します
スレッドT31 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
x.csynca();
}
}、 "t31");
//新しいT32を作成すると、T32はx.issyncb()を呼び出します
スレッドT32 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
y.csyncb();
}
}、 "t32");
t31.start();
t32.start();
}
public static void main(string [] args){
locktest3 demo = new locktest3();
demo.test3();
}
}
実行結果:
コードコピーは次のとおりです。
T31:CSYNCA
T31:CSYNCA
T31:CSYNCA
T31:CSYNCA
T31:CSYNCA
T32:CSYNCB
T32:CSYNCB
T32:CSYNCB
T32:CSYNCB
T32:CSYNCB
(04)同時にアクセスできます。 Issynca()はインスタンスメソッドであるため、x.issynca()はオブジェクトxのロックを使用します。したがって、それらに同時にアクセスできます。
コードコピーは次のとおりです。
// locktest4.javaソースコード
何かをクラスする{
public同期されたvoid issynca(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":issynca");
}
} catch(arternedexception ie){
}
}
public同期void issyncb(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":issyncb");
}
} catch(arternedexception ie){
}
}
public static同期void csynca(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":csynca");
}
} catch(arternedexception ie){
}
}
public static同期void csyncb(){
試す {
for(int i = 0; i <5; i ++){
swree.sleep(100);
system.out.println(thread.currentthread()。getname()+":csyncb");
}
} catch(arternedexception ie){
}
}
}
パブリッククラスLockTest4 {
何かx =新しい何か();
何かy = new何か();
//(04)x.issynca()とsomething.csynca()を比較する
private void test4(){
//新しいT41を作成すると、T41はx.issynca()を呼び出します
スレッドT41 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
x.issynca();
}
}、 "t41");
//新しいT42を作成すると、T42はx.issyncb()を呼び出します
スレッドT42 =新しいスレッド(
new runnable(){
@オーバーライド
public void run(){
Something.csynca();
}
}、 "t42");
t41.start();
t42.start();
}
public static void main(string [] args){
locktest4 demo = new locktest4();
demo.test4();
}
}
実行結果:
コードコピーは次のとおりです。
T41:Issynca
T42:CSYNCA
T41:Issynca
T42:CSYNCA
T41:Issynca
T42:CSYNCA
T41:Issynca
T42:CSYNCA
T41:Issynca
T42:CSYNCA