マルチスレッドの同期オブジェクト ロックと静的ロックの間の 8 ロック問題の理解

8 ロックの問題

2 つの問題があります: ロックのタイプと誰が
それをロックするかです。ロックのタイプ: 静的ロックはこのクラスのすべてのインスタンスのオブジェクトを対象とし、オブジェクト ロックは
現在のオブジェクトのみを対象とします。誰のためのロッカーですかsynchronized关键字?非静态メソッド静的ロックの対象synchronizedとなるのは、この種のキーワードを持つ静态メソッド
すべてであり、上記2点について、同一のオブジェクトであるかどうか、オブジェクトが呼び出すメソッドがどのようなロックタイプであるかに注意して判断してください。

ロック 1: 複数のスレッドが同じオブジェクトを使用して、synchronized キーワードを使用して異なる非静的メソッドを呼び出します。

分析: オブジェクト ロックは現在のオブジェクトのみを対象とし、ロックは synchronized キーワードを持つすべての非静的メソッドを対象とします。

public class Application {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Phone phone = new Phone();
        new Thread(()->{
    
    phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone.sendCall();},"B").start();
    }
   }
class Phone{
    
    
    synchronized void sendSMG(){
    
    
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
    
    
        System.out.println("打电话");
    }
}

結果:
ここに画像の説明を挿入
考え方 1:为什么A线程与B线程之间启动要睡一会?
コードは順番に実行されますが、スレッドの開始時期はオペレーティング システムが決定できます。A が最初に準備完了状態になりますが、オペレーティング システムは B を最初に開始することを選択する可能性があります。A スレッドと B スレッドは、開始時にしばらくスリープさせて、A スレッドが最初に開始されるようにします。OSの処理は非常に速いため、たとえ1秒の間隔であってもOSには大きな時間差が生じ、AとBが一緒ではないため、Aが先に起動する可能性が高くなります。

考え方 2: 为什么结果是这样?
2 つの重要なポイント:
同じオブジェクトであること、ロックの種類が同じであること
(スレッドが最初に開始され、オブジェクト ロックを取得します。オブジェクト ロックは解放されます)、同期されたオブジェクト ロックを持つメソッドは呼び出すことができません、待つことしかできません。A スレッドが実行を終了してロックを解放するまで、B スレッドはロックを取得して実行を続けることができます。

考え方 3:既然sendSMG()方法先执行,如果在方法中睡一会,sendCall()方法会不会先执行?
前述したように、スレッド A はロックを取得した後、最初に sendSMG() メソッドを実行します。メソッド内の sleep() ではロックが解放されないため、実行時間が長すぎてもロックが解放される前にロックが解放されません。実行が完了した場合、B 同期オブジェクトロックを使用したメソッドを実行するためのロックは取得できません
考え方 4:如果Phone有一个普通方法,没有带synchronized锁,B线程启动后即使sendSMG()方法没有执行完毕,这个普通方法会被执行吗?
通常のメソッドにはオブジェクトロックがなく、B は実行時に A がロックを解放するのを待つ必要はありません, したがって、B が開始されていれば、すぐに実行できます。スレッド A もこの共通メソッドを呼び出す場合、スレッド A と B の両方が同時にこのメソッド内に存在する可能性があります。

ロック 2: ロック 1 に基づいて、スレッド A によって実行されるメソッドの実行時間を増やし、B が実行に参加できるようにします。

上記の考え方 3 を検証すると、A スレッドが最初に実行を開始するのではなく、sendSMG() メソッドが最初に実行されることが証明され、B スレッドが sendCall() メソッドを呼び出すが、A スレッドが呼び出さないという問題に追いつきます。 sendSMG() メソッドを実行してオブジェクトのロックを解放します。B 単に sendCall() メソッドを実行する機会がありません。一定時間後に B スレッドが開始されるため、オブジェクト ロックは最初に A によって取得されます。ロックが取得されている限り、オブジェクト内で複数のスレッドは、同期されたオブジェクト ロックを使用してメソッドを実行するスレッドを 1 つだけ持つことができます。

public class Application {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    

        Phone phone = new Phone();
        new Thread(()->{
    
    phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone.sendCall();},"B").start();
    }
}

class Phone{
    
    
    synchronized void sendSMG(){
    
    
        try {
    
     TimeUnit.SECONDS.sleep(2); // 注意:我这里特意为2s使得这是B线程一定启动了 测试:B线程的sendCasll方法会不会先执行。} catch (InterruptedException e) {
    
    }
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
    
    
        System.out.println("打电话");
    }
}

このコードは、ロック 1 に基づいて sendMsg() の実行時間を増やすだけです。結果はロック 1 と同じで、1 秒待つとコンソールに「メッセージ送信」と表示され、その後「通話」と表示されます
ここに画像の説明を挿入

ここに画像の説明を挿入
スレッド A がオブジェクト ロックを取得した後、sendSMG() メソッドを実行し、コンソールに「送信メッセージ」を出力し、1 秒間スリープしてロックを解放します。スレッド B はロックを取得し、sendCall() メソッドを実行し、すぐにコンソールに「call」を出力します。

ロック 3: 複数のスレッドが同じオブジェクトを使用し、1 つのスレッドがオブジェクト ロックのあるメソッドを実行し、1 つのスレッドが通常のメソッドを実行します。

分析: オブジェクト ロックは synchronized の非静的メソッドをロックし、通常のメソッドはスコープをロックしません
推測: 通常のメソッドは synchronized の影響を受けず、より速く実行されるスレッドを最初に呼び出すことができます。

public class Application {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    

        Phone phone = new Phone();
        new Thread(()->{
    
    phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone.sendHello();},"B").start();
    }
}

class Phone{
    
    
    synchronized void sendSMG(){
    
    
        try {
    
     TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {
    
    }
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
    
    
        System.out.println("打电话");
    }
    void sendHello(){
    
    
        System.out.println("hello");
    }
}

結果:
ここに画像の説明を挿入
通常のメソッドではオブジェクト ロックを取得する必要がまったくないため、スレッド B の実行はスレッド A のオブジェクト ロックの解放を待つ必要がありません。

考えてみます: A スレッドが通常のメソッドも呼び出してから、このように通常のメソッドを再調整した場合はどうなるでしょうか?
ここに画像の説明を挿入
ここに画像の説明を挿入
結果:
ここに画像の説明を挿入


上記では、同じオブジェクトを使用して同期オブジェクト ロックの問題について説明しており、以下では、不同オブジェクトを使用して同期オブジェクト ロックの問題について説明しています。


ロック 4: 複数のスレッドが異なるオブジェクトを使用して、オブジェクト ロックを持つ異なるメソッドを呼び出す

分析: オブジェクト ロック: 現在のオブジェクトに対してのみ有効なので、異なるオブジェクト間での使用は無効です

public class Application {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    

        Phone phone1 = new Phone();
        Phone phone2 = new Phone();
        new Thread(()->{
    
    phone1.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone2.sendCall();},"B").start();
    }
}

class Phone{
    
    
    synchronized void sendSMG(){
    
    
        try {
    
     TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {
    
    }
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
    
    
        System.out.println("打电话");
    }
    void sendHello(){
    
    
        System.out.println(Thread.currentThread().getName()+"进入");
        try {
    
     TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) {
    
     }
        System.out.println("hello");
        System.out.println(Thread.currentThread().getName()+"离开");
    }
}

結果:
ここに画像の説明を挿入
考察:明明A线程先启动获取了对象锁,为什么B线程的方法在A线程没有执行完毕就开始执行?
ロックの種類と誰がロックしているかという 2 つの問題があります。
スレッド A と B は異なるオブジェクトを使用しているため、オブジェクト ロックには無効です。スレッド B によって操作されるオブジェクトにはスレッド B の独自のロックがあり、スレッド A によって操作されるオブジェクトにはスレッド A の独自のロックがあります。この 2 つは同じオブジェクトではないため、ロックは異なります。オブジェクト ロック タイプを実行するメソッドの場合、スレッド A のオブジェクト ロックはスレッド B のオブジェクト ロックをロックできません。
考え方:如果锁住不同对象的?
現時点では、クラス ロックを使用する必要があります。これは、異なるオブジェクトも同じクラスからインスタンス化され、クラス ロックを使用できるためです。 used 、別のオブジェクトによっても認識されるロックを生成します。


静的ロックについては以下で紹介します


ロック 5: 複数のスレッドが、同じオブジェクト上のそれぞれの静的ロックでメソッドを呼び出します。

分析: 静的ロック、このタイプのすべてのオブジェクトは有効です。Locked は同期された静的メソッドです。

public class Application {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    
        Phone phone = new Phone();
        new Thread(()->{
    
    phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone.sendCall();},"B").start();
    }
}

class Phone{
    
    
     synchronized static void sendSMG(){
    
    

        try {
    
     TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {
    
    }
        System.out.println("发送消息");
    }
     synchronized static void sendCall(){
    
    
        System.out.println("打电话");
    }
}

効果:
ここに画像の説明を挿入
メソッドへの static の追加は、同じオブジェクトであるかどうかに関係なく、同じクラスのロックと同等です。このタイプのインスタンス化されたオブジェクトである限り、オブジェクトがロックを取得して解放するまで、オブジェクトは実行できません。クラスロックを使用した it メソッド

ロック 6: 複数のスレッドと複数のオブジェクトが、それぞれの静的ロックでメソッドを呼び出します。

効果はロック 5 と同じです。すべてクラス ロックであるメソッドでは、それらが同じオブジェクトであるかどうかは区別されません。オブジェクトが実行されている限り、それが同じオブジェクトであるかどうかに関係なく、オブジェクトはこのクラスのクラス ロックを持つメソッドの実行を待つことしかできません。
考え方:如果线程A使用对象1调用的是静态锁方法,线程B使用对象2调用的是普通方法,A先启动,那么对象2调用普通方法是需要等待A释放静态锁吗?
もちろんそうではありません。通常のメソッドにはロックがまったくなく、クラス ロックによって制限できないからです。


以下では、静的ロックとオブジェクト ロックが混在しています。


ロック 7: 複数のスレッドが同じオブジェクトに対してオブジェクト ロック メソッドと静的ロック メソッドをそれぞれ呼び出します。

分析: オブジェクト ロックと静的ロックが存在しますが、それらの間には関係がありません。
または、次の 2 つの重要な点に注意してください。それは同じオブジェクトですか? はい、呼び出されるメソッドは同じロック タイプですか? 不是1 つは静的ロック、もう 1 つはオブジェクト ロックです。2
つの異なる方法。ロックの種類が異なるため、それらの間には関係がありません。

public class Application {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    

        Phone phone = new Phone();
        new Thread(()->{
    
    phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
    
    phone.sendCall();},"B").start();
    }
}

class Phone{
    
    
    synchronized void sendSMG(){
    
    

        try {
    
     TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {
    
    }
        System.out.println("发送消息");
    }
    static synchronized void sendCall(){
    
    
        System.out.println("打电话");
    }
}

効果:
ここに画像の説明を挿入
スレッド A が最初に実行されますが、スレッド A がオブジェクト ロックを取得します。スレッド B が開始すると、オブジェクト ロックではロックできないクラス ロックを取得します。そのため、B は、A が実行を終了してスレッドを解放するまで待つ必要はありません。実装する前にクラスをロックします。

考え方 1:如果是两个线程调用的同一个方法加上静态锁呢?
静的メソッドのロックは、同じオブジェクトであるかどうかに関係なく、1 つのスレッドがロックを取得している限り、クラス レベルのロックであるため、同じオブジェクトであるかどうかとは関係ありません。 、実行後ロックが解放されるまで、他のスレッドはこのメソッドを実行できません。ただし、他の非静的ロック方法も実装できます。

思考 2: 如果A先拿到类锁,B后拿到对象锁,那B用等到A释放锁后再去执行吗?也就是说类锁与对象锁是否有包含关系?(異なるオブジェクト)
ここに画像の説明を挿入

証明:クラス ロックとオブジェクト ロックは、スコープが異なる 2 種類のロックです (オブジェクト ロックは現在のオブジェクトのみを対象とし、クラス ロックはこのクラスのすべてのインスタンスのオブジェクトを対象とします)。ただし、クラス ロックにはオブジェクト ロックは含まれません。

ロック 8: 複数のスレッドの異なるオブジェクトがそれぞれオブジェクト ロックのメソッドと静的ロックのメソッドを呼び出します。

ロック 7 思考 2 と同様に、スレッド A が取得するのはこのオブジェクト 1 に属するオブジェクト ロックであり、スレッド B が取得するのはすべてのオブジェクトに属するクラス ロックです。2 つの呼び出しメソッドで使用されるロックの種類は異なり、より速く実行された方が先に出力され、待ち時間の問題は発生しません。

おすすめ

転載: blog.csdn.net/m0_52889702/article/details/128847416