次のコードは、特定のクラス メソッドを同期する方法を示しています。
次のようにコードをコピーします。
パッケージの mythread;
パブリック クラス SyncThread は Thread を拡張します
{
プライベート静的文字列同期 = "";
プライベート文字列メソッドタイプ = "";
プライベート静的 void メソッド(String s)
{
同期された(同期)
{
同期 = s;
System.out.println;
一方 (真);
}
}
パブリック void メソッド1()
{
メソッド("メソッド1");
}
public static void staticMethod1()
{
メソッド("静的メソッド1");
}
public void run()
{
if (methodType.equals("static"))
staticMethod1();
else if (methodType.equals("nonstatic"))
メソッド1();
}
public SyncThread(String メソッドタイプ)
{
this.methodType = メソッドタイプ;
}
public static void main(String[] args) が例外をスローする
{
SyncThread サンプル 1 = 新しい SyncThread("非静的");
SyncThread サンプル 2 = 新しい SyncThread("static");
サンプル1.start();
サンプル2.start();
}
}
実行結果は次のとおりです。
次のようにコードをコピーします。
方法1
静的メソッド1
多くの読者は、上記の実行結果を見て驚かれるかもしれません。上記のコードでは、method1 メソッドと staticMethod1 メソッドは同期に静的文字列変数 sync を使用します。これら 2 つのメソッドのうち同時に実行できるのは 1 つだけであり、どちらのメソッドも 014 行目の無限ループ ステートメントを実行します。したがって、出力結果は、method1 または staticMethod1 のいずれかのみになります。しかし、このプログラムは両方の文字列を出力します。
この結果の理由は非常に単純で、行 012 を見るとわかります。この行で sync の値が変更されていることがわかります。ここではJavaのString型についてお話したいと思います。 String 型は、Java の他の複合型とは異なります。 String 型変数を使用する場合、一度変数に値を代入すると、Java は String 型の新しいインスタンスを作成します。次のコードに示すように:
次のようにコードをコピーします。
文字列 s = "こんにちは";
System.out.println(s.hashCode());
s = 「世界」;
System.out.println(s.hashCode());
上記のコードで。最初の s と再割り当てされた s の hashCode 値は異なります。 String クラスのインスタンスの作成には new を使用する必要がないため、String 型変数を同期する場合は、この変数に値を代入しないように注意してください。代入しないと、変数は同期されません。
sync の新しいインスタンスが行 012 で作成されているため、method1 が最初に実行されると仮定すると、method1 が行 013 のコードを実行すると、sync の値は元の値ではなくなり、method1 は依然として sync 変数を初期値にロックします。 。このとき、たまたま staticMethod1 が synchronized(sync) に対して実行されるため、staticMethod1 メソッドでロックされる同期と、method1 メソッドでロックされる同期が異なってしまいます。そのため、2 つのメソッドの同期は破棄されます。
上記の問題の解決策は、もちろん 012 行を削除することです。この行は、クラス変数を使用してメソッドを同期するときに、同期ブロック内で同期変数の値が変更されると、メソッド間の同期が破壊されることを示すためだけにこの例に追加されています。この状況を完全に回避するには、同期変数を定義するときに Final キーワードを使用します。たとえば、上記のプログラムの行 005 は次の形式に変更できます。
次のようにコードをコピーします。
プライベート最終静的文字列同期 = "";
Final キーワードを使用した後、sync は定義時にのみ値を割り当てることができ、後で変更することはできません。プログラム内の別の場所で sync に値が割り当てられている場合、プログラムはコンパイルされません。 Eclipse などの開発ツールでは、プロンプトが間違った場所に直接表示されます。
同期ブロックは 2 つの観点から理解できます。クラスメソッドの観点から理解すると、対応するメソッドはクラス変数を通じて同期できます。クラス変数の観点から理解すると、同期ブロックを使用して、クラス変数に同時に 1 つのメソッドのみがアクセスできるようにすることができます。どの角度から理解しても本質は同じで、クラス変数を使用して同期ロックを取得し、同期ロックの相互排他によって同期を実現するというものです。
注: 同期ブロックを使用する場合、同期ブロックはパラメーターとしてオブジェクトのみを使用できることに注意する必要があります。単純な型の変数 (int、char、boolean など) の場合、同期には synchronized を使用できません。