JAVA:代码块的哪个部分同步关键字块?并解释这个僵局

时间:2014-08-12 19:56:24

标签: java multithreading oracle deadlock

我有疑问:
1。同步方法的代码的哪一部分,同步块?
例如:

public class example{

  public synchronized void f1(){
    //some code....
     f2();
    }
    public synchronized void f2()
    {
      //some code...
    }
}
public void main(String[[] args)
{
   Thread t1 = new Thread(new Runnable()
   {public void run(){f1();)},
          t2 = new Thread(new Runnable()
   {public void run(){f2();};
   t1.start();
   t2.start();

}

所以在t1开始后,t2无法启动 - 因为它等待t1。但是,t1开始做f2,这是否意味着t2可以进入f1?

如果可以,请解释这个死锁示例。我没有得到它。来源:http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s"
                + "  has bowed to me!%n", 
                this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s"
                + " has bowed back to me!%n",
                this.name, bower.getName());
        }
    }

    public static void main(String[] args) {
        final Friend alphonse = new Friend("Alphonse");
        final Friend gaston = new Friend("Gaston");
        new Thread(new Runnable() {
            public void run() { alphonse.bow(gaston); }}).start();
        new Thread(new Runnable() {
            public void run() { gaston.bow(alphonse); }}).start();
    }
}

2 个答案:

答案 0 :(得分:1)

Java中的synchronized方法锁定整个方法,更重要的是,它锁定了调用该方法的对象的实例。这意味着同一对象中的两个同步方法共享同一个锁,因此不能由不同的线程同时执行。

E.g。在下面的课程

public class myClass
{
  synchronized void method1()
  {

  }

  synchronized void method2()
  {

  }
}
永远不能在同一个对象上同时调用

method1()method2(),因为代码相当于:

public class myClass
{
  void method1()
  {
    synchronized(this)
    {
      // ...
    }
  }

  void method2()
  {
    synchronized(this)
    {
      // ...
    }
  }
}

如果您希望两种方法在不同的锁上独立同步,那么您可以执行以下操作:

public class myClass
{
  private final Object method1Lock = new Object();
  private final Object method2Lock = new Object();

  void method1()
  {
    synchronized(method1Lock)
    {
      // ...
    }
  }

  void method2()
  {
    synchronized(method2Lock)
    {
      // ...
    }
  }
}

答案 1 :(得分:0)

死锁示例:由于两个线程(执行进程的实例,甚至是轻量级进程,因为某些操作系统会调用它们)获取相同的锁,其中一个将始终获得锁定而另一个必须等​​到首先获得锁(这是由JVM确定的,将JVM视为操作系统 - 有人必须保证锁的原子性,这取决于JVM)。 在示例中,一个线程将执行 bow(),然后执行 bowBack(),但是当 bowBack()执行时,另一个线程已经在同一个锁上执行了获取(通过调用 bow()),使另一个线程处于等待状态,这取决于第一个线程,并且第一个线程在调用时取决于相同的锁strong> bowBack() - 发生循环依赖,即死锁。

来自oracle doc的

  

首先,两次调用同步方法是不可能的   在同一个对象上进行交错。当一个线程正在执行时   对象的synchronized方法,所有其他调用的线程   同一对象块的同步方法(暂停执行)   直到第一个线程完成对象。

该示例进一步指出其极有可能将发生死锁,这意味着它不必发生。这是因为获得锁定的第一个线程可以在第二个线程获得锁定之前完成执行其 bowBack(),即调用 bow()(我使用获取锁定作为操作系统理论的术语,它提出了这个曾经的原始语言),由JVM决定哪个线程可以在什么时间执行(执行方案的线程的实际调度,以及更改执行线程) (称为上下文切换)有点昂贵,因此JVM可能决定让第一个线程执行更长的时间段而不会发生死锁。考虑线程调度最好通过将其视为一个非常随机的事情,如果迟早会发生死锁,一次运行程序(或另一种循环,例如产生两个线程的方法,如示例中所示) )可能会给另一个可能没有的僵局。多线程是关于考虑锁定什么,而不是以一种可能产生死锁的方式组合锁的过程。

也许你应该尝试通过例如一个线程暂停一段时间(例如在进入弓形之前尝试1毫秒,然后再说 gaston.bow())来看到死锁的例子并看到发生了什么,记住这样做是没有保证的,睡觉一个线程实际上并没有使代码线程安全,死锁只会不那么频繁发生。

然后介绍几个更多线程 bow() - 睡眠确实有帮助,或者只是推迟问题....?