4

我正在准备 SCJP 考试,但无法完全理解同步。在第 6 行,我读到 main 中运行的线程需要锁定“b”。为什么它需要锁定这个对象?我的理解是,同步的代码块是一个保护区,任何时候只有一个线程可以进入?继续前进,main 中的线程释放此锁并等待 'b 中的线程完成其 run 方法。然后,'b' 中的线程用于通知 main 中的线程它已完成。但是,它看起来并没有在这里通知任何特定的线程。这个例子来自 Sierra 和 Bates SCJP 的书。任何可以阐明这一点的光都将不胜感激。谢谢

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

        **synchronized(b) {  //line 6**
            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() {  
        System.out.println("K");  
        synchronized(this) {  
            for(int i=0;i<100;i++) {  
                total += i;  
            }  
            notify();  
        }  
    }  
}
4

4 回答 4

2

两个线程在这里同步Object,即b. main()首先获取锁,然后调用, b.wait()释放锁并等待有人调用notify()b

这意味着当run()方法(在这种情况下被调用 on b)调用notify()时, this 将再次唤醒该main()方法。

所以,获得锁在b这里并不重要,重要的是两个线程都获得相同的锁,否则wait()/notify()合作将无法进行。

于 2012-09-22T12:43:41.787 回答
2

在第 6 行,我读到 main 中运行的线程需要锁定“b”。为什么它需要锁定这个对象?

因为这就是那条线的作用。它获取该资源。其他线程可以获得其他同步块,但没有其他线程可以获取该对象的锁。

它看起来不像在这里通知任何特定线程。

这是真实的。该程序不知道将通知哪个线程,甚至不知道是否会通知任何线程。作为开发人员,您可能会得出结论,有一个特定的线程将被通知,可能是因为它是唯一的线程等待()。

于 2012-09-22T12:43:50.730 回答
2

这是一个非常极端的案例,你不会那样做。
发生的事情是main线程在ThreadB对象和wait.
ThreadB完成时 anotify被提升并因此main被唤醒并继续。
但这不是您通常会编写的代码,即使用Thread对象用于synchronization.
要查看这是多么极端的情况,只需notifyThreadB.
由于您在Thread对象上同步并且实现在 a 完成后引发通知,因此代码仍然可以工作Thread
这种行为违反直觉且容易出错。

于 2012-09-22T12:45:17.543 回答
0

该代码利用wait()机制来确保result由 other 计算ThreadB

要等待对象,您需要获得对该对象的锁定,即line 6出现synchronized (b)在图片中的位置。

执行相同程序的更好方法是使用Thread#join()方法。

public final void join()
            throws InterruptedException

Waits for this thread to die.
于 2012-09-22T13:20:52.813 回答