从SCJP 6书中了解多线程

时间:2013-03-29 11:00:43

标签: java multithreading

以下代码在SCJP6书中

class ThreadA {
    public static void main(String [] args) {
        ThreadB b = new ThreadB();
        b.start();

        synchronized(b) {
            try {
                System.out.println("Waiting for b to complete...");
                b.wait();
            } catch (InterruptedException e) {}
            System.out.println("Total is: " + b.total);
        }
    }
}

class ThreadB extends Thread { 
     int total;

     public void run() {
         synchronized(this) {
             for(int i=0;i<100;i++) {
                 total += i;
             }
             notify();
         }
     }
 }

先前的代码不会导致死锁,因为线程a和b都锁定b(在相应的同步块中)?

我遗失了一些东西,但不太确定它是什么。

2 个答案:

答案 0 :(得分:6)

最有可能的执行如下:

  • b.start()与正在执行的run方法之间存在轻微延迟
  • 主线程因此设法获取b上的锁并进入synchronized
  • 然后等待b释放锁
  • run开始执行时,监视器可用(或将很快提供),以便它可以进入synchronized
  • 完成后,它会通知b它可以停止等待
  • 主线程完成。

但是,根据线程调度,run首先执行是不可能的,在这种情况下,主线程可以在b.wait()上永远等待。例如,如果您通过在Thread.sleep(100)之后插入一个小的b.start()来帮助实现这种情况,那么您应该观察到这种情况。

底线:它是一个可能遇到活动问题的臭代码(因为锁可用,它本身并不是死锁)。

答案 1 :(得分:4)

取决于。

来自wait方法的文档 -

  

使当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法。换句话说,此方法的行为就像它只是执行call wait(0)一样。

     

当前线程必须拥有此对象的监视器。线程发布   此监视器的所有权,并等待另一个线程通知   在这个对象的监视器上等待通过a唤醒的线程   调用notify方法或notifyAll方法。线程然后   等到它可以重新获得监视器的所有权并恢复   执行。

所以,如果你考虑这两种情况 -

  • 如果ThreadA首先获取对象b的锁定,它将等待,从而导致释放锁定,这将导致ThreadB继续其工作。
  • 如果ThreadB首先获得锁定,那么它将继续它的工作,释放锁定,然后ThreadA将启动。接下来,ThreadA将等待对象锁b,这可能导致它永远等待。