0. 主要な質問コード
次のコードは、2 つのスレッドが同時に i に対して累算操作を実行し、それぞれが 1,000,000 回実行されると予想されますが、それを複数回実行すると、確実に i=2000000 になります。 , i の値は常に 2000000 未満であることがわかります。これは、2 つのスレッドが同時に i に書き込むと、一方のスレッドの結果が他方のスレッドを上書きしてしまうためです
これを根本的に解決するには。問題は、i を操作するときに複数のスレッドが完全に同期していることを確認する必要があります。つまり、スレッド A が i に書き込むとき、スレッド B は書き込むことができないだけでなく、読み込むことさえできません。
1. synchronized キーワードの役割
2. 同期キーワードの使用法
次のコードは、指定されたオブジェクトに対して同期されます。ここで、指定されたオブジェクトは静的である必要があります。そうでないと、新しいスレッドを作成するたびに、オブジェクトは相互に共有されなくなり、ロックの意味が消えてしまいます。インスタンス メソッド
synchronized キーワードはインスタンス メソッドに作用します。つまり、スレッドは、increase() メソッドに入る前に、現在のインスタンスのロックを取得する必要があります。これには、Thread インスタンスを使用する場合、以下を作成する必要があります。同じ Runnable オブジェクト インスタンスを使用してください。それ以外の場合、スレッドのロックは同じインスタンス上になく、ロック/同期の問題について話すことはできません。
メインのプレフィックスに注意してください。メソッド インスタンス メソッドでのキーワードの正しい使用法を説明する 3 行です。
2.3 静的メソッドに直接作用する 静的メソッドで synchronized キーワードを使用するため、2 つのスレッドが同じメソッドを指す必要はありません。上記の例。Runnable メソッド。メソッド ブロックは現在のインスタンスではなく、現在のクラスのロックを要求する必要があるため、スレッドは引き続き正しく同期されます。3. 上記より。たとえば、カウンター アプリケーションが必要な場合、データの正確性を保証するために、当然カウンターをロックする必要があることがわかっています。そのため、次のコードを記述します。上記のコードでは、出力 i が非常に小さいことがわかります。これは、スレッドが安全ではないことを示しています。この問題を説明するには、整数から始める必要があります。Java では、整数は文字列と同様に不変です。オブジェクトが作成されると、それは変更できません。Integer = 1 の場合は、常に 1 になります。このオブジェクトを 2 にしたい場合は、i++ を実行するたびにのみ Integer を作成できます。これは、Integer の valueOf メソッドを呼び出すことと同じです。Integer の valueOf メソッドのソース コードを見てみましょう:
Integer.valueOf() は、実際には新しいメソッドを返す傾向があります。整数オブジェクトを作成し、その値を i にコピーします
これで、複数のスレッド間では、i++ が新しいオブジェクトを指すため、スレッドはロックするたびに異なるオブジェクト インスタンスをロードする可能性があるため、問題の原因がわかりました。は非常に簡単で、上記の 3 つの同期メソッドのいずれかを使用するだけです