孩子不是海子 2017-05-25 02:03 采纳率: 9.1%
浏览 3839

java多线程之notify()的唤醒顺序

在网上看到的额都说notify()的唤醒顺序是随机的,可是自己做的一个实验显示并不是如此:package adad;

public class MyThreadFactory {

// 线程A是否处于等待状态的标志  
 private boolean isThreadAWaiting;  
    // 线程B是否处于等待状态的标志  
    private boolean isThreadBWaiting;  
    // 线程C是否处于等待状态的标志  
    private boolean isThreadCWaiting;  


    public MyThreadFactory() {  
        isThreadAWaiting = true;  
        isThreadBWaiting = true;  
        isThreadCWaiting = true;  
    }  

    /** 
     * 对象锁 
     */  
    private final Object object = new Object();  

    /** 
     * 该线程作为一个唤醒线程 
     */  
    public void startWakenThread() {  
        Thread t = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                synchronized (object) {  
                    System.out.println("唤醒线程开始执行...");  
                    // 首先释放线程A  
                    quitThreadA();  
                }  
            }  
        });  
        t.start();  
    }  

    /** 
     * 启动线程A 
     */  
    public void startThreadA() {  
        Thread t = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                synchronized (object) {  
                    System.out.println("线程A开始等待...");  
                    try {  
                        for (; ; ) {  
                            if (!isThreadAWaiting) break;  
                            object.wait();  
                        }  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }  
                    System.out.println("线程A结束...");  
                    // 线程A结束后,暂停2秒释放线程B  
                    try {  
                        Thread.sleep(2000);  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }  
                    quitThreadB();  
                }  
            }  
        });  
        t.start();  
    }  

    /** 
     * 启动线程B 
     */  
    public void startThreadB() {  
        Thread t = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                synchronized (object) {  
                    System.out.println("线程B开始等待...");  
                    try {  
                        for (; ; ) {  
                            if (!isThreadBWaiting) break;  
                            object.wait();  
                        }  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }  
                    System.out.println("线程B结束...");  
                    // 线程B结束后,暂停2秒释放线程C  
                    try {  
                        Thread.sleep(2000);  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }  
                    quitThreadC();  
                }  
            }  
        });  
        t.start();  
    }  

    /** 
     * 启动线程C 
     */  
    public void startThreadC() {  
        Thread t = new Thread(new Runnable() {  
            @Override  
            public void run() {  
                synchronized (object) {  
                    System.out.println("线程C开始等待...");  
                    try {  
                        for (; ; ) {  
                            if (!isThreadCWaiting) break;  
                            object.wait();  
                        }  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }  
                    System.out.println("线程C结束...");  

                    try {  
                        Thread.sleep(1000);  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }  
                    System.out.println("所有线程执行完毕!");  
                }  
            }  
        });  
        t.start();  
    }  

    /** 
     * 线程A退出等待 
     */  
    private void quitThreadA() {  
        isThreadAWaiting = false;  
        object.notify();  
    }  

    /** 
     * 线程B退出等待 
     */  
    private void quitThreadB() {  
        isThreadBWaiting = false;  
        object.notify();  
    }  

    /** 
     * 线程C退出等待 
     */  
    private void quitThreadC() {  
        isThreadCWaiting = false;  
        object.notify();  
    }  
   public static void main(String[] args) {  
        MyThreadFactory factory = new MyThreadFactory();  
        factory.startThreadB();//这儿的启动顺序注意
        factory.startThreadA();  

        factory.startThreadC();  

        try {  
            Thread.sleep(3000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        factory.startWakenThread();  
    }  

}

在网上找的这个例子,刚开始启动顺序是ABC,我改成BAC后运行程序多次都唤醒不了,这不正是说明唤醒跟其启动(启动的的时候会有个进入等待池也就是先进先出的顺序吗)

  • 写回答

3条回答 默认 最新

  • 双木有兮木有辛 2017-05-26 09:29
    关注

    这个程序,貌似不能用作 线程唤醒无序的例子,每个线程里有两个变量来控制是否能运行,一个是object对象锁,一个是标记变量。

    你的唤醒函数的设置标记的顺序是 ABC,但是object的notify不能保证按照ABC唤醒。因此你这个程序实际运行起来应该是有问题的

    换句话说,即使你用object.notify(); 唤醒了B。 但是因为标记状态没有被A设置,因此唤醒不了3个线程。

    何况你虽然是顺序start三个线程,但不代表这三个线程就一定是按你调用的顺序启动的。 三个线程太少,看不出随机性。

    我自己写了一个测试随机唤醒的程序。 结果发现虽然结果不是有规律,但是也不是完全没有规律。 粗看下一个规律是。前面几个休眠的线程会按照顺序唤醒,后面的线程则会倒序唤醒。 具体还需要研究下。

     import java.util.LinkedList;
    import java.util.List;
    
    public class ThreadRunSort {
    
        /** 
         * 对象锁 
         */  
        private final Object object = new Object();  
        private List<Integer> sleep = new LinkedList<>();
        private List<Integer> notify = new LinkedList<>();
        /** 
         * 该线程作为一个唤醒线程 
         */  
        public void startThread(int i) {  
            Thread t = new Thread(new Runnable() {  
                @Override  
                public void run() {  
                    synchronized (object) {  
                        try {
                            System.out.println(Thread.currentThread().getName()+"进入休眠");
                            sleep.add(i);
                            object.wait();
                            System.out.println(Thread.currentThread().getName()+"线程已经唤醒");
                            notify.add(i);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }  
                }  
            });  
            t.setName("Thread"+i);
            t.start();  
        }  
    
        public static void main(String[] args) {  
            ThreadRunSort a = new ThreadRunSort();
            for(int i =1;i<22;i++){
                a.startThread(i);
            }
    
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println();
            for(int i =1;i<22;i++){
                synchronized (a.object) {
                    a.object.notify();
                }
            }
    
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("休眠顺序"+a.sleep);
            System.out.println("唤醒顺序"+a.notify);
    
    
        }    
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器