当前位置: 首页 > 知识库问答 >
问题:

Hibernate线程会失去监控锁的所有权吗?

伊飞光
2023-03-14

我想用自己的眼睛验证睡眠和等待之间的区别。

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

为此我做了一个测试:

步骤:

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

    }

}

编辑:

好的,我理解我的错误-我在等待这个-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个答案

方茂
2023-03-14

这里有一个更好的方法使测试工作,并显示它的工作。你的问题是没有正确等待,无缘无故地使用了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();
      }
    }
  }
孟俊晖
2023-03-14

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

 类似资料:
  • 假设要写一个在后台启动线程的函数,想通过新线程返回的所有权去调用这个函数,而不是等待线程结束再去调用;或完全与之相反的想法:创建一个线程,并在函数中转移所有权,都必须要等待线程结束。总之,新线程的所有权都需要转移。 这就是移动引入std::thread的原因,C++标准库中有很多资源占有(resource-owning)类型,比如std::ifstream,std::unique_ptr还有std

  • 问题内容: 我需要知道,hibernate的会话是否是线程安全的。但是很明显,新会话将附加到每个线程以执行。但是我的问题是,如果在一个线程中我已经更新了某个实体的某个值,那么这将在同一时间执行期间反映在另一个线程中吗? 我的问题是,当我依次从两个线程启动更新时,值会正确更新,但是当我几乎完全启动更新时,它将失败。 例如 表的当前阶段。 我正在尝试以下: 当我尝试在循环中运行上述代码(例如10)时,

  • 问题内容: 我知道会话不是线程安全的。我的第一个问题:将实体传递给另一个线程,对它做一些工作,然后将其传递回原始线程并进行更新,是否安全? 我的第二个问题:在一个线程中创建一个实体并将其保存在另一个线程中是否安全? 编辑 我忘了提到实体是为快速加载而专门配置的 问题答案: 否。该实体已附加到会话中,并包含链接到该会话的代理(以延迟自身加载)。因此,这样做将使用多个线程中的会话。由于会话不是线程安全

  • 我正在http://www.python-course.eu/threads.php的帮助下学习python线程处理。这段代码的解释让我很困惑: 代码: 读取num_thread的值 一个新的int实例将增加或减少1(我认为一个新的int对象将被创建) 将新值分配给num_threads 像这样的错误发生在增量赋值的情况下: 第一个线程读取变量num_threads,它的值仍然是0。令人困惑的是:

  • 问题内容: 帮助客户解决他们遇到的问题。我更多地是sysadmin / DBA的人,所以我在努力帮助他们。他们说这是内核/环境中的错误,在我坚持要在他们的代码中或寻求供应商对OS的支持之前,我试图证明或证明这一点。 发生在Red Hat和Oracle Enterprise Linux 5.7(和5.8)上,应用程序用C ++编写 他们遇到的问题是主线程启动一个单独的线程来执行可能长时间运行的TCP

  • 我正在使用Spring Cloud和@EnableZuulProxy,是否可以通过/hystrix.stream使用hystrix监视application.yml中配置的所有路由?在下面的示例中,我希望有一个简单的方法来监视所有对下游产品服务的请求。我理解我可以在产品服务本身上做到这一点,但是否有可能监视Zuul请求。这对于任何非自有(第三方)且不能用@hystrixcommand注释的下游服务