Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 两个同步语句。它们是如何工作的?_Java_Multithreading - Fatal编程技术网

Java 两个同步语句。它们是如何工作的?

Java 两个同步语句。它们是如何工作的?,java,multithreading,Java,Multithreading,我试图在一个方法中运行另一个方法中的synchronized语句 MyClass public class MyClass { private Object lockObject = new Object(); public void testFirst() { synchronized (lockObject) { System.out.println("Entered testFirst() sync");

我试图在一个方法中运行另一个方法中的synchronized语句

MyClass

public class MyClass {

    private Object lockObject = new Object();

    public void testFirst() {
        synchronized (lockObject) {
            System.out.println("Entered testFirst() sync");
            testSecond();
            System.out.println("Leaving testFirst() sync");
        }
    }

    private void testSecond() {
        synchronized (lockObject) {
            System.out.println("Entered testSecond() sync");
        }
    }

}
public class MyClass {

    private Object lockObject = new Object();

    public void testFirst() throws InterruptedException {
        // Here is something that should not be synchronized 
        synchronized (lockObject) {
            System.out.println("testFirst() is about to fall asleep. "
                    + Thread.currentThread().getName());
            Thread.sleep(2000);
            System.out.println("testFirst() woke up. " + Thread.currentThread().getName());
        }
    }

}
Main

package com.replanet;

public class Main {

    public static void main(String[] args) {

        MyClass myClass = new MyClass();
        myClass.testFirst();
    }

}
输出

Entered testFirst() sync
Entered testSecond() sync
Leaving testFirst() sync
testFirst() is about to fall asleep. Thread-0
testFirst() woke up. Thread-0
testFirst() is about to fall asleep. Thread-1
testFirst() woke up. Thread-1
我期待另一个输出

Entered testFirst() sync
Leaving testFirst() sync
Entered testSecond() sync

为什么不
testSecond()
等到
testFirst()
完成它的工作呢?

您看到了这种看似奇怪的行为,因为每个锁都与请求它的线程相关联,一旦有了锁,您就将它一直保留到解锁

在代码中,您两次获得相同的锁,因此第二次尝试立即成功,因为您已经拥有了它

请参阅以供参考:

当一个线程正在为一个对象执行同步方法时,所有调用同一对象块的同步方法的其他线程(暂停执行),直到第一个线程处理完该对象为止


由于要进入第一个
synchronized
部分,您必须拥有对象的锁
lockObject
,当您到达第二个
synchronized
部分时,您仍然拥有它,因此它将继续。当运行
testFirst
时,
testSecond
中的
synchronized
块不会更改任何内容。

因为testSecond()testFirst()相关联

控制流程如下所示:-

System.out.println("Entered testFirst() sync");
       System.out.println("Entered testSecond() sync");
System.out.println("Leaving testFirst() sync");

同步是围绕称为内在锁或监视锁的内部实体构建的。
每个对象都有一个与之关联的内在锁。按照惯例,需要以独占和一致方式访问对象字段的线程必须在访问对象字段之前获取对象的固有锁,然后在处理完这些字段后释放固有锁。线程在获取锁和释放锁之间拥有内在锁。只要一个线程拥有一个内在锁,其他线程就不能获得相同的锁。另一个线程在尝试获取锁时将阻塞


因此,您的线程是lockObject的所有者,因此它可以使用lockObject输入块内的所有代码。请记住以下几点:

  • synchronized
    块是可重入的:当您通过
    synchronized
    语句持有一个锁时,您可以使用同一监视器输入另一个
    synchronized
    块-在您的情况下,没有什么阻止您从
    testFirst
    调用
    testSecond
  • 现在假设这两个方法使用不同的监视器,您仍然会得到相同的输出,因为没有其他线程持有
    testSecond
  • 如果这两个方法使用了两个不同的锁,而另一个线程持有
    testSecond
    中使用的锁,
    testFirst
    的执行不会跳过对
    testSecond
    的调用并继续,它将阻塞,直到锁再次可用

    • 我编辑了我发布的代码。synchronized语句很有意义,不是吗

      MyClass

      public class MyClass {
      
          private Object lockObject = new Object();
      
          public void testFirst() {
              synchronized (lockObject) {
                  System.out.println("Entered testFirst() sync");
                  testSecond();
                  System.out.println("Leaving testFirst() sync");
              }
          }
      
          private void testSecond() {
              synchronized (lockObject) {
                  System.out.println("Entered testSecond() sync");
              }
          }
      
      }
      
      public class MyClass {
      
          private Object lockObject = new Object();
      
          public void testFirst() throws InterruptedException {
              // Here is something that should not be synchronized 
              synchronized (lockObject) {
                  System.out.println("testFirst() is about to fall asleep. "
                          + Thread.currentThread().getName());
                  Thread.sleep(2000);
                  System.out.println("testFirst() woke up. " + Thread.currentThread().getName());
              }
          }
      
      }
      
      神话阅读

      public class MyThread extends Thread {
      
          private MyClass myClass;
      
          public MyThread(MyClass myClass) {
              this.myClass = myClass;
          }
      
          @Override
          public void run() {
              try {
                  myClass.testFirst();
              } catch (InterruptedException e) {
                  interrupt();
              }
              super.run();
          }
      
      }
      
      用法

      package com.replanet;
      
      public class Main {
      
          public static void main(String[] args) {
              MyClass myClass = new MyClass();
              MyThread mThread = new MyThread(myClass);
              MyThread anotherThread = new MyThread(myClass);
              mThread.start();
              anotherThread.start();
          }
      
      }
      
      输出

      Entered testFirst() sync
      Entered testSecond() sync
      Leaving testFirst() sync
      
      testFirst() is about to fall asleep. Thread-0
      testFirst() woke up. Thread-0
      testFirst() is about to fall asleep. Thread-1
      testFirst() woke up. Thread-1
      

      +1供ICP参考。您显然不了解锁。请阅读:@fredcrs,谢谢。我将阅读文档。我正在读Fred Long写的《Java并发指南》一书,只是补充说:如果不是这样,这个方法就会死锁itself@OldCurmudgeon,
      每个锁都与请求的线程关联。不是用线程,而是用对象,不是吗?@RedPlanet-很确定是
      线程
      锁定了
      对象
      。也许我误解了您的意思。@RedPlanet-找到了引用-它说当一个线程正在为一个对象执行同步方法时,所有其他线程都会为同一个对象块调用同步方法(暂停执行),直到第一个线程处理完该对象为止。