0

睡眠と待機の違いを自分の目で確かめたかった。

待機は、監視ロックの所有権を解放するため、同期ブロックでのみ実行できます。スリープはモニター ロックとは関係ありませんが、既にモニター ロックの所有者であるスレッドは、スリープしている場合でもその所有権を失うべきではありません。

そのために私はテストをしました:

手順:

  1. 同期ブロックで 5 秒間待機するスレッドを開始しました。
  2. 3 秒待機し、モニター ロックを取得する別のスレッドを開始し (スレッド A が待機しているため)、モニター ロックを保持したまま 5 秒間スリープします。

期待される結果: スレッド - A は 8 秒後にのみロックを再取得し、スレッド - B は​​同期ブロックを終了してモニター ロックを最終的に解放します。

実結果。スレッド - A は 5 秒後にモニター ロックを取得します。

ここで何が起こったのか説明してもらえますか?

public static void main(String[] args) {

    Runnable r1 = new Runnable() {

        @Override
        public void run() {

            System.out.println("r1 before synch block");
            synchronized (this) {

                System.out.println("r1 entered synch block");
                try {

                    wait(5000);
                    System.out.println("r1 finished waiting");

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        }

    };

    Runnable r2 = new Runnable() {

        @Override
        public void run() {

            System.out.println("r2 before synch block");
            synchronized (this) {

                System.out.println("r2 entered synch block");
                try {

                    Thread.currentThread();
                    Thread.sleep(5000);
                    //wait(5000);
                    System.out.println("r2 finished waiting");

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        }

    };

    try {

        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);

        t1.start();
        Thread.currentThread();
        Thread.sleep(3000);
        t2.start();

        t1.join();
        t2.join();
        System.out.println(Thread.currentThread().getName() + " Finished joining");

    } catch (Exception e) {

        e.printStackTrace();

    }

}

編集:

OK、エラーを理解しました-これを待っています-r1/r2であり、同じオブジェクトではありません。

今、私はそれを変更し、両方が同じオブジェクトを取得しました - メインのクラスインスタンス。1. r1 は Main.this のモニター ロックの所有権を取得します。 2. r1 はそれを解放します。3. r1 が再取得しようとすると、例外が発生します。

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at Main$1.run(Main.java:28)
at java.lang.Thread.run(Unknown Source)
on synchronized (Main.this)

ここで何が問題なのですか?

public static void main(String[] args) {

        Main main = new Main();
        main.test();

    }

    public void test() {

        Runnable r1 = new Runnable() {

            @Override
            public void run() {

                System.out.println("r1 before synch block");
                synchronized (Main.this) {

                    System.out.println("r1 entered synch block");
                    try {

                        wait(5000);
                        System.out.println("r1 finished waiting");

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

            }

        };

        Runnable r2 = new Runnable() {

            @Override
            public void run() {

                System.out.println("r2 before synch block");
                synchronized (Main.this) {

                    System.out.println("r2 entered synch block");
                    try {

                        Thread.currentThread();
                        Thread.sleep(5000);
                        //wait(5000);
                        System.out.println("r2 finished waiting");

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

            }

        };

        try {

            Thread t1 = new Thread(r1);
            Thread t2 = new Thread(r2);

            t1.start();
            Thread.currentThread();
            Thread.sleep(3000);
            t2.start();

            t1.join();
            t2.join();
            System.out.println(Thread.currentThread().getName() + " Finished joining");

        } catch (Exception e) {

            e.printStackTrace();

        }

    }
4

2 に答える 2

2

2 つのスレッドは、実際には 2 つの異なるロックを保持しています。クラス名を MyClass とすると、2 行の synchronized (this) を synchronized (MyClass.this) に変更して、2 つのスレッドが同じロックを保持するようにします。

于 2012-12-26T13:55:10.920 に答える
0

これは、テストを機能させ、機能することを示すためのはるかに優れた方法です。あなたの問題は、あなたが正しく待たず、理由もなくThread.currentThread()を使用したことでした。

ところで、信号を失うことなく待機通知メカニズムの信号を使用したい場合は、このリンクを読むことをお勧めします。

public class MAIN
  {
  public static void main(final String[] args)
    {
    final Object sync =new Object();
    final long startTime=System.currentTimeMillis();
    final Runnable r1=new Runnable()
      {
        @Override
        public void run()
          {
          System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 before synch block");
          synchronized(sync)
            {
            System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 entered synch block");
            try
              {
              sync.wait(5000);
              System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 finished waiting");
              }
            catch(final InterruptedException e)
              {
              e.printStackTrace();
              }
            }
          System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 exited synch block");
          }
      };
    final Runnable r2=new Runnable()
      {
        @Override
        public void run()
          {
          System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 before synch block");
          synchronized(sync)
            {
            System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 entered synch block");
            try
              {
              Thread.sleep(5000);
              System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 finished waiting");
              }
            catch(final InterruptedException e)
              {
              e.printStackTrace();
              }
            }
          System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 exited synch block");
          }
      };
    try
      {
      final Thread t1=new Thread(r1);
      final Thread t2=new Thread(r2);
      t1.start();
      Thread.sleep(3000);
      t2.start();
      t1.join();
      t2.join();
      System.out.println((System.currentTimeMillis()-startTime)/1000+":  Finished joining");
      }
    catch(final Exception e)
      {
      e.printStackTrace();
      }
    }
  }
于 2012-12-26T18:37:12.713 に答える