インスタンス メソッドを変更します。通常の同期メソッドの場合、ロックは現在のインスタンス オブジェクトです。
静的メソッドを変更します。静的同期メソッドの場合、ロックは現在の Class オブジェクトです。
メソッド コード ブロックを変更します。同期メソッド ブロックの場合、ロックは同期括弧内に設定されたオブジェクトです。
スレッドが同期されたコード ブロックにアクセスしようとすると、ロックを取得する必要があり、完了後 (または例外が発生した後)、ロックを解放する必要があります。では、ロックは正確にどこに存在するのでしょうか?一緒に探検しましょう!
ただし、この記事は誰でも見つけることができるので、その使用法については誰もがすでによく知っていると思います。その使用法と、マルチスレッド状況でデータが混乱する理由については詳しく説明しません。の解説!いくつかの使用方法のみを記載していますので、ご参考にしてください。
インスタンス メソッドを変更します。通常の同期メソッドの場合、ロックは現在のインスタンス オブジェクトです
インスタンス メソッドを変更する必要はありませんこれを使用するには、同じインスタンスに同期を追加した後、アトミック操作を完了するためにスレッドをキューに入れる必要がありますが、これは 同じインスタンス
が使用されている場合にのみ有効になることに注意してください。
正の例:
<code>/**<br> * @author huangfu<br> */<br>public class ExploringSynchronized implements Runnable {<br> /**<br> * 共享资源(临界资源)<br> */<br> static int i=0;<br> public synchronized void add(){<br> i++;<br> }<br><br> @Override<br> public void run() {<br> for (int j = 0; j add();<br> }<br> }<br><br> public static void main(String[] args) throws InterruptedException {<br> ExploringSynchronized exploringSynchronized = new ExploringSynchronized();<br> Thread t1 = new Thread(exploringSynchronized);<br> Thread t2 = new Thread(exploringSynchronized);<br> t1.start();<br> t2.start();<br> //join 主线程需要等待子线程完成后在结束<br> t1.join();<br> t2.join();<br> System.out.println(i);<br><br> }<br>}</code>
反例:
<code>/**<br> * @author huangfu<br> */<br>public class ExploringSynchronized implements Runnable {<br> /**<br> * 共享资源(临界资源)<br> */<br> static int i=0;<br> public synchronized void add(){<br> i++;<br> }<br><br> @Override<br> public void run() {<br> for (int j = 0; j add();<br> }<br> }<br><br> public static void main(String[] args) throws InterruptedException {<br> Thread t1 = new Thread(new ExploringSynchronized());<br> Thread t2 = new Thread(new ExploringSynchronized());<br> t1.start();<br> t2.start();<br> //join 主线程需要等待子线程完成后在结束<br> t1.join();<br> t2.join();<br> System.out.println(i);<br><br> }<br>}</code>
この場合、メソッドに synchronized を追加しても役に立ちません。 、ロックは現在のインスタンス オブジェクトです。インスタンス オブジェクトは異なるため、それらの間のロックは当然同じではありません。
静的メソッドの変更静的同期メソッドの場合、ロックは現在の Class オブジェクトです
定義からわかります。つまり、彼のロックはクラス オブジェクトです。つまり、上記のクラスを例にとると、通常のメソッドのロック オブジェクトは new ExploringSynchronized()
で、静的メソッドに対応するロック オブジェクトは次のとおりです。 ExploringSynchronized.class
したがって、静的メソッドに同期ロックを追加すると、インスタンスを再作成しても、取得されるロックは同じままになります。
<code>package com.byit.test;<br><br>/**<br> * @author huangfu<br> */<br>public class ExploringSynchronized implements Runnable {<br> /**<br> * 共享资源(临界资源)<br> */<br> static int i=0;<br> public synchronized static void add(){<br> i++;<br> }<br><br> @Override<br> public void run() {<br> for (int j = 0; j add();<br> }<br> }<br><br> public static void main(String[] args) throws InterruptedException {<br> Thread t1 = new Thread(new ExploringSynchronized());<br> Thread t2 = new Thread(new ExploringSynchronized());<br> t1.start();<br> t2.start();<br> //join 主线程需要等待子线程完成后在结束<br> t1.join();<br> t2.join();<br> System.out.println(i);<br><br> }<br>}</code>
もちろん、結果は期待どおりです 200000
変更されたメソッド コード ブロック、同期されたメソッド ブロックの場合、ロックは内部にあります同期されたブラケット構成オブジェクト!
<code>package com.byit.test;<br><br>/**<br> * @author huangfu<br> */<br>public class ExploringSynchronized implements Runnable {<br> /**<br> * 锁标记<br> */<br> private static final String LOCK_MARK = "LOCK_MARK";<br> /**<br> * 共享资源(临界资源)<br> */<br> static int i=0;<br> public void add(){<br> synchronized (LOCK_MARK){<br> i++;<br> }<br> }<br><br> @Override<br> public void run() {<br> for (int j = 0; j add();<br> }<br> }<br><br> public static void main(String[] args) throws InterruptedException {<br> Thread t1 = new Thread(new ExploringSynchronized());<br> Thread t2 = new Thread(new ExploringSynchronized());<br> t1.start();<br> t2.start();<br> //join 主线程需要等待子线程完成后在结束<br> t1.join();<br> t2.join();<br> System.out.println(i);<br><br> }<br>}</code>
同期されたコード ブロックの場合、括弧内はロック オブジェクトです。この文字列オブジェクトなどを使用できます。
Java での synchronized
の実装は、Monitor
オブジェクトの入口と出口に基づいています。それは、明示的な同期 (明示的な monitorenter
および monitorexit
命令を使用してコード ブロックを変更する) または暗黙的な同期 (メソッド本体を変更する) です。
コード ブロックを変更する場合のみ、monitorenter
および monitorexit
命令に基づいて実装され、メソッドを変更する場合は、別の意味で達成されました!それについては後で話します!
実装全体の最下層を理解する前に、メモリ内のオブジェクトの構造の詳細について一般的に理解していただければ幸いです。
synchronized で使用されるロックはオブジェクト ヘッダーに存在します。配列オブジェクトの場合、仮想マシンはオブジェクトの保存に 3 ワード幅を使用し、非配列オブジェクトの場合、オブジェクト ヘッダーの保存に 2 ワード幅を使用します。仮想マシンという単語では、1 ワード幅は 4 バイトに相当します。主な構造は、
Mark Word と
Class Metadata Address で構成されており、その構造は次のとおりです:
ヘッダー オブジェクトの構造 | ##説明#32/64 ビット | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
32/64bit | クラスメタデータアドレス | が格納されます。構成タイプ データポインタ | ||||||||
32/64bit (配列) | A配列の長さ | 配列の長さ | ||||||||
25bit | 4bit | 1bit は偏ったロックです | 2bit ロックフラグ | |
---|---|---|---|---|
オブジェクトのハッシュコード | オブジェクトの世代年齢 | 0 | 01 |
以上がJava の synchronized キーワードは、スレッド同期を実現するために使用されます。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。