たとえて言えば、オブジェクトは大きな家のようなもので、ドアは常に開いています。家にはたくさんの部屋 (別名メソッド) があります。これらの部屋はロックされているか (同期方式)、ロックが解除されています (通常方式)。部屋のドアには鍵があり、この鍵ですべての施錠された部屋を開けることができます。さらに、このオブジェクトのメソッドを呼び出したいすべてのスレッドと、この家の特定の部屋に入ろうとしている人々を比較します。必要なのはこれだけです。これらがどのように連携するかを見てみましょう。
ここでまず前提条件を明確にします。オブジェクトには少なくとも 1 つの同期メソッドがあります。それ以外の場合、このキーは意味を持ちません。もちろん、私たちにはそのようなテーマはありません。
ある人が鍵のかかった部屋に入りたいと思って、家のドアのところに来ると、そこに鍵があるのを見ます(まだ誰もその鍵のかかった部屋を使いたくないことを示しています)。そこで彼は部屋に上がり、鍵を受け取り、計画通りに部屋を使いました。彼は施錠された部屋を使用するたびにすぐに鍵を返却することに注意してください。たとえ鍵のかかった部屋を2つ続けて利用したい場合でも、途中で鍵を返却しなければならない。
したがって、通常の鍵の使用は「使うときに借りて、使ったらすぐに返す」が原則です。
現時点では、ロックが解除された部屋は制限なく他の人が使用できます。1 つの部屋を 1 人で使用することも、2 人で使用することもできます。しかし、誰かが鍵のかかった部屋に入りたい場合は、ドアまで走って見なければなりません。鍵を持っていればもちろん持って帰ることができますが、鍵を持っていない場合は待つしかありません。
多くの人が鍵を待っている場合、鍵が返されたときに誰が最初に鍵を受け取るでしょうか?保証されていません。先ほどの例で鍵のかかった部屋を 2 つ続けて使いたい男性のように、鍵を返却したときに他の人が鍵を待っている場合、その男性が再び鍵を入手できる保証はありません。 (JAVA 仕様では、休息後に Thread.sleep() が実行に戻るまでにどれくらいの時間がかかるか、同じ優先順位のどのスレッドが最初に実行されるか、いつ実行されるかなどの保証がないことが多くの場所で明確に述べられています。オブジェクトにアクセスするためのロックが解放されると、待機プール内の複数のスレッドがロックを解除します。どのスレッドが最初にロックを取得しますか?などなど、最終的な判断はJVMにあると思いますが、なぜ保証がないのかというと、JVMが上記の判断をする際には、単純に1つの条件だけで判断するのではなく、多くの条件に基づいて判断するためです。多くの判定条件を発言すると、JAVA に影響を与える可能性があります。 SUN は知的財産保護のための保証をしていないのかもしれませんが、それは理解できます。しかし、一見ランダムな現象であっても、実際にはコンピュータ自体が動作するため、これらの不確実性は完全に不確かではないと私は考えています。コンピュータを勉強したことがある人なら誰でも、コンピュータの乱数の学名が擬似乱数であることを知っています。また、それは人間がそうありたいからかもしれません。確かに、それは非常に面倒ですし、あまり意味がありませんので、よくわからない場合は、よくわからないでください。)
同期されたコード ブロックをもう一度見てみましょう。同期方法とは少し異なります。
1. サイズの点では、同期コード ブロックは同期メソッドよりも小さくなります。同期されたコード ブロックは、ロックされた画面で区切られたロックされていない部屋内のスペースと考えることができます。
2. 同期コード ブロックは、別のオブジェクトのキーを手動で指定することもできます。この画面の鍵を開けるために使用できる鍵を指定するのと同じで、この家の鍵を使用して開くこともできます。この場合、他の家の鍵を開く必要があります。その鍵を取得し、その家の鍵を使用してこの家のロックされた画面を開きます。
あなたが入手した別の家の鍵は、その家の鍵のかかっていない部屋に他人が入るのを妨げるものではないことに注意してください。
同期されたコード ブロックを使用する理由は何ですか?私は次のようになるべきだと思います。まず、プログラムの同期部分は動作効率に影響します。メソッドは通常、最初にいくつかのローカル変数を作成し、次にこれらの変数に対して計算や表示などのいくつかの操作を実行します。 ; および同期カバー コードが増えるほど、効率への影響は大きくなります。そのため、私たちは通常、その影響範囲をできるだけ小さく抑えるよう努めます。やり方は?同期されたコードブロック。同期する必要があるメソッドの部分 (操作など) のみを同期します。
さらに、同期コード ブロックでキーを指定できるため、この機能には、一定期間内にオブジェクトのキーを占有するという追加の利点もあります。通常の状況でキーを使用する原則について前に述べたことを思い出してください。これらは普通の状況ではありません。取得したキーは永久に返されるのではなく、同期されたコード ブロックを終了するときにのみ返されます。
先ほどの、鍵のかかった部屋を 2 つ続けて使いたかった男性のたとえを使ってみましょう。 1つの部屋を使用した後、別の部屋を引き続き使用するにはどうすればよいですか?同期されたコード ブロックを使用します。まず別のスレッドを作成し、同期コード ブロックを作成し、そのコード ブロックのロックを家の鍵に向けます。次に、そのスレッドを開始します。そのコードブロックに入ったときに家の鍵をつかむことができる限り、そのコードブロックを出るまでそれを保管しておくことができます。言い換えれば、この部屋のすべての施錠された部屋を横断することも、睡眠することもできます (10*60*1000)。ただし、ドアのところで鍵を待っているスレッドがまだ 1000 個あります。とても楽しいです。
sleep() メソッドとキーの相関関係について話しましょう。スレッドがキーの取得後に強制的に sleep() され、同期コンテンツが完了していない場合、キーはそのまま残ります。キーは、再度実行されてすべての同期コンテンツが完了するまで返されません。覚えておいてください、その人は仕事で疲れて休憩しに行っただけで、やりたいことは終わっていませんでした。他人が部屋に入ってきて部屋が散らかることを防ぐため、寝るときも唯一の鍵を体に付けなければならなかった。
最後に、なぜ各ドアに 1 つの鍵ではなく、各ドアを開くのに 1 つの鍵が必要なのかと疑問に思う人もいるかもしれません。これは純粋に複雑さの問題だと思います。 1つのドアに1つの鍵があれば確かに安全ですが、多くの問題を伴います。鍵の生成、保管、取得、返却など。同期方法の数が増えると、その複雑さは幾何級数的に増加し、効率に重大な影響を与える可能性があります。これはトレードオフの問題とみなすことができます。少しでもセキュリティを高めるために効率を大幅に下げることは、なんと望ましくないことでしょう。