2013-02-25 36 views
3

我想在另一个同步语句中运行一个方法。两个同步语句。他们如何工作?

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

} 

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 

我预期另一个输出。

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

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

+0

+1供ICP参考。 – L0j1k 2013-02-25 11:26:04

+0

你很自然地不理解锁。 请阅读:http://docs.oracle.com/javase/tutorial/essential/concurrency/ – fredcrs 2013-02-25 11:34:20

+0

@fredcrs,谢谢。我会阅读文档。我正在阅读Fred Long撰写的名为“Java并发指南”的书。 – 2013-02-25 13:22:36

回答

4

你会看到这个看似奇怪的行为,因为每个锁都与请求它的线程相关联,一旦你锁定了锁定,直到你解锁。

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

参考文献见here

当一个线程正在执行同步方法为对象,即调用针对同一对象块(暂停执行)同步方法所有其他线程直到第一线程是用物体完成。

+0

只需添加:如果它不能以这种方式工作,则此方法将自己锁死 – jontro 2013-02-25 11:32:44

+0

@OldCurmudgeon,“每个锁都与请求的线程关联”。不是用线程而是用对象,不是吗? – 2013-02-25 11:36:04

+0

@RedPlanet - 很确定它是''Thread',它拥有'Object'上的锁。也许我误解了你/它。 – OldCurmudgeon 2013-02-25 11:40:39

3

由于进入第一​​部分,你必须有对象lockObject的锁,当你在第二​​节中,你仍然有它,所以它继续到达。当运行testFirst时,​​块中的testSecond没有任何变化。

1

Beause testSecond()testFirst()

控制流动酷似以下相关: -

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

同步是围绕被称为内部锁或监视器内部实体建锁。
每个对象都有一个与之相关的固有锁。按照惯例,需要独占且一致地访问对象字段的线程在访问对象之前必须先获取对象的内部锁,然后在完成内部锁时释放内部锁。据说一个线程拥有它获取锁定和释放锁定之间的固有锁定。只要线程拥有内部锁,其他线程就不会获得相同的锁。另一个线程在尝试获取锁时会阻塞。

所以你的线程是lockObject的所有者,因此它可以与lockObject输入所有代码块中

2

有几件事情要记住:

  • ​​块重入:当你持有锁通过​​声明,您使用相同的显示器可以进入另一个​​块 - 在你的情况下,没有什么能阻止你从哪打来testSecondtestFirst
  • 现在想象一下,2种方法ü SED显示器不同,你仍然会得到相同的输出,因为没有其他线程将举行的testSecond
  • 锁IF 2种方法使用了两种不同的锁另一个线程保持在testSecondtestFirst的执行中使用的锁将不会跳过呼叫testSecond并继续前进,它会阻止,直到锁再次可用
0

我编辑了我发布的代码。同步的陈述是有意义的,不是吗?

MyClass的

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

} 

MyThread的

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

} 

输出

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