线程调用notifyAll唤醒其他线程之后

写在前面

今天做老师给的多线程的作业,熟悉线程之间通信的方法,像wait,notify,notifyAll,通过调试代码后,产生了很多疑问,我都纷纷作了猜测,唯有这个疑问我还没搞清楚,网上也难以翻到:线程调用notifyAll唤醒其他线程后其自身的状态是怎样的?我给的猜想是进入就绪队列中。

寻找答案

通过对下面代码的调试,理清楚线程的走向。

public class lab3_3 {
    public static void main(String[] args) {
        Object lock = new Object();
        MyThread3_3 t1 = new MyThread3_3(0, 'A', lock);
        MyThread3_3 t2 = new MyThread3_3(1, 'B', lock);
        MyThread3_3 t3 = new MyThread3_3(2, 'C', lock);
        t1.start();
        t2.start();
        t3.start();
    }
}

class MyThread3_3 extends Thread {
    Object lock;
    char c;
    int flag;
    static int current = 0; //意味着先输出A字符

    public MyThread3_3(int flag, char c, Object lock) {
        this.flag = flag;
        this.lock = lock;
        this.c = c;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
*           synchronized (lock) {
                while (flag != current) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(c);
                current = ++current % 3;
                lock.notifyAll();
            }
        }
    }
}

上面代码是控制顺序输出“ABCABCABC”。首先我在*处设下断点调试,按顺序先后让后两个线程②③获得锁,由于第一个字符A应该由线程①来获得锁并输出,所以此时线程②③会直接调用wait方法进入等待队列,如下图:

image-20200414221137081

然后线程①获得锁,执行代码块,输出字符,最后调用notifyAll方法唤醒其他线程,还没走完代码块,此时状态如下图,线程②③都为MONITOR,在这里我猜测该状态是线程就绪状态,没有确切的证据,因为我网上翻不到。

image-20200414221433114

接着走过代码块,来到for循环的判断语句时,状态开始变了,如下图:

image-20200414221728074

只有线程③进入RUNNING状态,线程②还是就绪状态,这里之前我又尝试了不同顺序的调用wait方法,比如一开始是线程②③的顺序调用wait方法,我又换了③②的顺序调用wait方法,发现上面的结果真的不一样,唤醒后变成了最后一个线程③在就绪队列中。明明是先调用wait方法先进入等待队列的,为什么不是最先从就绪队列出来的?网上有找到说就绪队列是队列形式但实际上采用线程池的形式,CPU调度不一定按先进先出的顺序调度。不过我又多给出三个线程来调试,发现都是最后调用wait的方法,就第一个从就绪队列进到RUNNING状态,不由得让我做出猜测:线程以堆栈的形式进入等待队列,然后出栈进入就绪队列,就绪队列是队列的数据结构,所以最后进入等待队列的线程,优先从就绪队列中出来。当然,确切的证据还是没有。

接着上面的步骤,直接让线程①获得锁执行代码块,发现线程它的状态变为MONITOR(就绪)了,没法再直接调用,此时也只能调用线程③了,由于当前是字符B的输出,也就是应该线程②获得锁,所以线程③又调用wait方法进入等待队列中,此时线程②从就绪队列中出来了,变为RUNNING状态。这个步骤我又尝试了多次其他不同的顺序,于是又给出猜测,也是适合这次内容主题的猜测:线程①调用notifyAll方法唤醒其他线程后,自身无法再直接获得该锁,进入了就绪队列,而且是队列的末尾,符合了队列的特征。

写在最后

我只是给出多个猜测,可能是正确的也说不定哈哈🤭我就暂且这样想吧,毕竟多线程还有好多内容呢,而且不记下来恐怕日后会烟消云散。能力之外的深入探究,就待我归来之时再谈吧。

天色已晚,就写到这里。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章