睡眠线程会损失显示器锁定的所有权

时间:2012-12-26 13:49:39

标签: java multithreading wait monitor synchronized

我想在自己的眼中验证睡眠和等待之间的差异。

等待只能在同步块中完成,因为它释放了监视器锁的所有权。 睡眠与监视器锁定无关,而已经是监视器锁定所有者的线程在睡眠时不应失去其所有权。

为此我做了一个测试:

步骤:

  1. 启动一个在同步块中等待5秒的线程。
  2. 等待3秒并启动另一个获取监视器锁定的线程(因为Thread-A正在等待)并且只是在按住监视器锁定的情况下休眠5秒钟。
  3. 预期结果: 线程 - 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();
    
        }
    
    }
    

    编辑:

    好的,我理解我的错误 - 我在等待 - r1 / r2,而不是在同一个对象上。

    现在我更改了它并且都获取了同一个对象 - Main的类实例。 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();
    
            }
    
        }
    

2 个答案:

答案 0 :(得分:2)

这两个线程实际上有两个不同的锁。假设您的类名是MyClass,将两行synchronized(this)更改为synchronized(MyClass.this),这使得两个线程保持相同的锁。

答案 1 :(得分:0)

这是一个更好的方法来使测试工作,并表明它的工作原理。 你的问题是你没有正确等待并且无缘无故地使用了Thread.currentThread()。

顺便说一句,如果你想在不丢失信号的情况下使用wait-notifier机制的信号,我建议你阅读this link

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();
      }
    }
  }