関連する無料学習の推奨事項:Java 基本チュートリアル
8 ロックの問題のデモ
1. 標準アクセス
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
標準アクセスでは、最初に電子メールまたはテキスト メッセージを印刷します。
誰が最初に印刷されるかは関係ありません。それは CPU の実行に依存します。それらをアクティブにするのはメインスレッドです。後で誰が最初にスケジュールされるかはわかりません。
効果を確実にするために、A と B のコードの間に thread.sleep(100) を追加します。このとき、A が最初に出力されることを保証できます。
説明:
リソース クラスが存在する限り、それに含まれる同期メソッドの数に関係なく、スレッドが最初にリソース クラス内のいずれかの同期メソッドにアクセスする限り、これはロックされません。メソッドは、メソッドが配置されているリソース クラス全体です。つまり、ロックされているのはオブジェクトです。ロックするものは現在のメソッドではありません。
つまり、これらの同期メソッドはすべて同じリソース クラスに属し、リソース クラス全体がロックされます。
2. 電子メール メソッドで 4 秒間一時停止します。最初に電子メールまたはテキスト メッセージを印刷してください。
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
最初に電子メールを印刷してください。同期メソッドによって取得された電話オブジェクトのロックは、スリープによって解放されません。時間になるとすぐに実行されます。したがって、最初に電子メール メソッドを出力します。
説明:
これは質問 1 と似ています。
リソース クラスが存在する限り、同期メソッドがいくつあっても、スレッドが最初にリソース クラス内のいずれかの同期メソッドにアクセスする限り、このメソッドではなくメソッドがロックされます。リソースクラス全体。つまり、ロックされているのはオブジェクトです。ロックするものは現在のメソッドではありません。
例: モニターと私は同じ携帯電話を使用して電話をかける必要があります。通話を続けるには、モニターが通話を終了するまで待つ必要があります。彼が使用している間、しばらくモニターが切断されていたため、私はモニターが終了するのを待つことしかできませんでした。
#3. 通常のsayHello メソッドを追加します。最初に電子メールを印刷するか、hello
最初に hello を印刷してください/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); phone.sayHello(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
説明: 共通メソッドを追加した後、それが同期ロックとは何の関係もないことが判明しました。したがって、同期ロックが解除されるまで待つ必要はありません。ここに例を示します。モニターは携帯電話を使用して電話をかけました。そして、分隊長から携帯電話の充電ケーブルを借りたいのですが、この 2 つは相互に排他的ではないので、分隊長が電話を終える前に充電ケーブルを借りることができます。
4. 2 台の携帯電話で、最初に電子メールまたはテキスト メッセージを印刷してください
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); //phone.sayHello(); phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
5. 2 つの静的同期方法、同じ携帯電話の場合は、最初に電子メールまたはテキスト メッセージを印刷してください
/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public static synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); //phone.sayHello(); //phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
説明:質問 6 の分析と組み合わせます
6. 2 つの静的同期方法、2 台の携帯電話、最初に電子メールまたはテキスト メッセージを印刷してください
/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public static synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); //phone.sayHello(); phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
分析:
static クラスに属します。言い換えれば、彼は現在のオブジェクトの独立した個人に属していません。グローバルクラスです。これには、オブジェクト ロックとグローバル ロックの違いを考慮する必要があります。グローバル ロックはクラス ロックです。現時点では、1 台の電話機であっても複数の電話機であっても、それらはすべて同じ Phone クラスに属します。どのオブジェクトをロックしても、使用できるようになる前にロックが解除されるまで待たなければなりません。
7.1 静的同期方法、1 つの通常の同期方法、同じ携帯電話、最初に電子メールまたはテキスト メッセージを印刷してください
/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); //phone.sayHello(); //phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
1 つの静的同期方法, 普通のもの。同じ電話がロックされています。静的メソッドはクラスをロックします。これは 1 つの校門をロックするのと同じであり、もう 1 つは現在のオブジェクトをロックする通常の同期メソッドです。たとえば、普通の教師。ロックの対象が異なります。競合なし
8.1 静的同期方法、1 つの通常の同期方法、2 台の携帯電話、最初に電子メールまたはテキスト メッセージを印刷してください
/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); //phone.sayHello(); phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
8 ロック理論の説明
1. オブジェクト内に複数の同期メソッドがある場合、ある時点で 1 つのスレッドがいずれかの同期メソッドを呼び出す限り、他のスレッドは待つことしかできません。これらの同期されたメソッドにアクセスします。
現在のオブジェクトはロックされています。ロックされた後、他のスレッドは現在のオブジェクトの他の同期メソッドに入ることができません。
通常のメソッドを追加した後、同期ロックとは関係がないことがわかりました。 。
2 つのオブジェクトを交換すると、同じロックがなくなり、状況はすぐに変わります。
静的同期メソッドに切り替えた後、状況はすぐに変わりました
すべての非静的同期メソッドは同じロックを使用します ------- インスタンス オブジェクト自体が同期を実現します
2.synchronized は同期を実現しますof: Java のすべてのオブジェクトはロックとして使用できます。
具体的には、次の 3 つの形式で表されます。
プロセスが同期されたコード ブロックにアクセスしようとすると、最初にロックを取得する必要があります。終了するか例外をスローすることでロックを解放する必要があります。
つまり、インスタンス オブジェクトの非静的同期メソッドがロックを取得した後、インスタンス オブジェクトの他の非静的同期メソッドは、ロックを取得したメソッドがロックを解放するまで待機してから取得する必要があります。ロック。ただし、他のインスタンス オブジェクトの非静的同期メソッドは、インスタンス オブジェクトの非静的同期メソッドとは異なるロックを使用するため、取得したインスタンス オブジェクトの非静的同期メソッドを待たずに、独自のロックを取得できます。ロックを解除するにはロックを押します。
すべての静的同期メソッドも、同じロック、つまりクラス オブジェクト自体を使用します。
2 つのロックは 2 つの異なるオブジェクトであるため、静的同期メソッドと非静的同期メソッドの間に競合状態は発生しません。(問題 78)。つまり、1 つのロック クラスと 1 つのロック クラス、この 2 つは競合しません。
ただし、静的同期メソッドがロックを取得すると、他の静的同期メソッドはロックを取得する前に、そのメソッドがロックを解放するまで待つ必要があります。同じインスタンス オブジェクトの静的同期メソッド間であっても、異なるインスタンス オブジェクトの静的同期メソッド間であっても、同じクラスのインスタンス オブジェクトである限りは関係ありません。 (質問56)
以上がJava では、オブジェクト ロックとクラス ロックを完全に理解するのに役立つ 8 つのロックが導入されています。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。