0
class Useless {
    public static boolean b = true;

    public synchronized void u1() {
        try {
            while (b == true)
                wait();
        } catch (InterruptedException i) {
        }
    }

    public synchronized void u2() {
        if (b == true) {
            b = false;
        }
        notify();
    }
}

public class SleepMessages extends Thread {

private Useless u;

    public SleepMessages(Useless u) {
        this.u = u;
    }

    public void run() {
        String importantInfo[] = { "Mares eat oats", "Does eat oats" };
        for (int i = 0; i < importantInfo.length; i++) {
            u.u1();
            System.out.println(importantInfo[i] + " - " + getName());
            try {
                sleep(2000);
            } catch (InterruptedException e) {
            }
        }
    }

    public static void main(String args[]) throws InterruptedException {
        Useless u = new Useless();
        Thread t1 = new SleepMessages(u);
        t1.setName("t1");
        Thread t2 = new SleepMessages(u);
        t2.setName("t2");
        t1.start();
        t2.start();
        sleep(2000);
        System.out.println("Here they go!...");
        t1.interrupt();
        sleep(1000);
        t2.interrupt();
        u.u2();
        sleep(1000);
        u.u2();
    }
}

这个小程序的输出是: 来了!... 母马吃燕麦 - t1 母马吃燕麦 - t2 吃燕麦 - t2 吃燕麦 - t1

我的问题是为什么线程 t2 是唯一进入 catch(InterruptedException e) 的线程,为什么结果不是这样的:

他们来了!... 母马吃燕麦 - t1 母马吃燕麦 - t2 吃燕麦 - t1 吃燕麦 - t2

4

3 回答 3

1

我的问题是为什么线程 t2 是唯一进入 catch(InterruptedException e) 的线程,

在我看来,这t1.interrupt()正在中断 run() 方法中的睡眠。一旦你丢弃了 InterruptedException,就无法知道线程之前被中断过。

为什么结果不是这样的: 他们来了!... 母马吃燕麦 - t1 母马吃燕麦 - t2 吃燕麦 - t1 吃燕麦 - t2

Java 使用偏向锁定。这意味着最后一个获得锁的线程更有可能首先获得相同的锁。

于 2013-01-08T16:20:01.657 回答
0

Useless 只有一个实例,所以只有一个布尔值 b。一旦将其设置为 true,两个 SleepMessages 实例都可以离开等待循环,因此无论哪个碰巧有机会运行,或者如果多个 CPU 同时运行线程,两者都会。

于 2013-01-08T16:32:46.330 回答
0

当我测试你的代码时,两个线程都被中断而没有问题,所以我不确定你为什么认为任何一个都没有进入 catch 块。

该练习似乎是在u1()第一次使用中断(触发线程以打印其第一条消息)并b第二次设置布尔值(触发第二条消息)时打破等待。

对于interrupt(),顺序是相当可预测的,t1将有足够的时间u1()在主线程在中断之前获得的第二次睡眠中到达下一次调用t2

u2()部分而言,订单的可预测性要低得多。两者t1t2在同一台显示器上等待。呼叫可能会notify()唤醒任何一个。醒来的人打印第二条消息,再睡一会儿然后停下来。第二个notify()唤醒在监视器上等待的一个线程。

所以最后两条消息的顺序是不确定的。

最后的一些建议:您似乎想要实现的行为可能更容易使用CyclicBarrier

于 2013-01-08T18:59:44.223 回答