javaはどうやってマルチスレッドの順番を実行しますか?


シーン
プログラムを作成して、三つのスレッドを起動します。三つのスレッドのnameはそれぞれA、B、Cです。各スレッドは自分のID値をスクリーンに5回印刷します。印刷順序はABCABC…
synchronizedを使って実現します。

public class MyService
{
    private int flag = 1;
    
    public synchronized void printA(){
        
        while (flag != 1)
        {
            try
            {
                this.wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        System.out.print(Thread.currentThread().getName());
        flag = 2;
        this.notifyAll();
    }
    public synchronized void printB(){
        while (flag != 2)
        {
            try
            {
                this.wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        System.out.print(Thread.currentThread().getName());
        flag = 3;
        this.notifyAll();
    }
    public synchronized void printC(){
        while (flag != 3)
        {
            try
            {
                this.wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        System.out.print(Thread.currentThread().getName());
        flag = 1;
        this.notifyAll();
    }
}
ここの判定条件ではifではなくwhileを使っていますが、この二つの違いは何ですか?スレッドがwaitの状態から呼び覚まされ、ロックを獲得するとAがnofityAll()を呼んでBを起動し、Cが起動するとBとCのどちらが先にロックを獲得するかは不明です。Cが先にロックを獲得したら、Cは続けて印刷を実行します。これは私達の期待と違っています。そこで私たちはwhileを使いました。Cがロックされてからflaggaを判断します。もしまだ実行されていないなら、再度wait状態に入ります。この時AとCは共にwait状態であり、ロックを得るのはBであり、私達が望む順序で印刷することができる。
テストクラス

package testABC;

public class TestMain
{
    public static void main(String[] args)
    {
//      ,      ,     ID   A,B,C;,        ID       5 ,     ABCABC...
//        MyService service = new MyService();
        MyService2 service = new MyService2();
        
        Thread A = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                for (int i = 0; i < 5; i++)
                {
                    service.printA();
                }
            }
        });
        A.setName("A");
        Thread B = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                for (int i = 0; i < 5; i++)
                {
                    service.printB();
                }
            }
        });
        B.setName("B");
        Thread C = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                for (int i = 0; i < 5; i++)
                {
                    service.printC();
                }
            }
        });
        C.setName("C");
        
        A.start();
        B.start();
        C.start();
    }
}

ロックで実現

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService2
{
    private int flag = 1;
    private Lock lock = new ReentrantLock();
    private Condition conditionA = lock.newCondition();
    private Condition conditionB = lock.newCondition();
    private Condition conditionC = lock.newCondition();

    public void printA()
    {
        try
        {
            lock.lock();
            if (flag != 1)
            {
                try
                {
                    conditionA.await();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
            System.out.print(Thread.currentThread().getName());
            flag = 2;
            conditionB.signal();
        }
        finally
        {
            lock.unlock();
        }

    }

    public void printB()
    {
        try
        {
            lock.lock();
            if (flag != 2)
            {
                try
                {
                    conditionB.await();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
            System.out.print(Thread.currentThread().getName());
            flag = 3;
            conditionC.signal();
        }
        finally
        {
            lock.unlock();
        }

    }

    public void printC()
    {
        try
        {
            lock.lock();
            if (flag != 3)
            {
                try
                {
                    conditionC.await();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
            System.out.print(Thread.currentThread().getName());
            flag = 1;
            conditionA.signal();
        }
        finally
        {
            lock.unlock();
        }
    }
}

LOCKを使用すると、Whileを使用しなくてもいいです。conditionで指定されたスレッドを起動することができます。同時に、まずconditionA.signalを呼び出す必要があります。ロック・ロック()を再起動します。java.lang.IllgalMonitoStation異常を投げます。unlockを呼び出した後、現在のスレッドはこのモニタオブジェクトのconditionの所有者ではないからです。つまり、このスレッドがロックオブジェクトを持つ場合にのみ、このロックオブジェクトが使用されます。
この異常なブログについて:java.lang.Illegel MonitonterStation Exceptionについて
アプリの説明

public class IllegalMonitorStateExceptionextends RuntimeException
投げられた異常は、あるスレッドが対象のモニターを待っているか、または他の待ち対象のモニターに通知しようとしていますが、それ自体がモニターのスレッドを指定していません。
以下のバージョンから開始します。
JDK 1.0
また、参照してください:
Object.notify()は、Object.notifyAll()、Object.wait()、Object.wait(long)、Object.wait(long,int)は、表を列記します。
つまり現在のスレッドはこの対象モニターの所有者ではありません。つまり、現在のスレッドでオブジェクトをロックするには、ロックされたオブジェクトをこのラインで操作する方法が必要です。
notify()、notifyAll()、wait()、wait(long)、wait(long、int)の操作は、IllagalMonitoStation異常を報告します。
たとえば:
exappmle 1は、ロック方法が属する例示的なオブジェクト:

public synchronized void method(){
    //       :this.notify()...
    //      notify()...
}
exappmle 2,ロック方法が属するインスタンスのクラス:

public Class Test{
 public static synchronized void method(){
    //    :Test.class.notify()...
 }
}
exapple 3は、他のオブジェクトをロックします。

public Class Test{
public Object lock = new Object();
 public static void method(){
    synchronized (lock) {
     //     lock.notify();
    } 
 }
} 
ここでは、javaがマルチスレッドの順番をどのように実現するかについての記事を紹介します。javaマルチスレッドの順番については、以前の記事を検索したり、以下の関連記事を見たりしてください。これからもよろしくお願いします。