美文网首页
关于wait()方法的使用

关于wait()方法的使用

作者: 全麦土司 | 来源:发表于2020-01-13 17:16 被阅读0次

    1、关于使用wait()方法为什么要加锁(否则会抛出 IllegalMonitorStateException):为了预防饥饿线程的产生(长期没有得到运行的线程)。
    如下所示:

    // 线程A 的代码
    while(!condition){ // 不能使用 if , 因为存在一些特殊情况, 使得线程没有收到 notify 时也能退出等待状态
        wait();
    }
    // do something
    
    // 线程 B 的代码
    if(!condition){
        // do something ...
        condition = true;
        notify();
    }
    

    现在考虑, 如果wait() 和 notify() 的操作没有相应的同步机制, 则会发生如下情况

    【线程A】 进入了 while 循环后(通过了 !condition 判断条件, 但尚未执行 wait 方法), CPU 时间片耗尽, CPU 开始执行线程B的代码
    【线程B】 执行完毕了 condition = true; notify(); 的操作, 此时【线程A】的 wait() 操作尚未被执行, notify() 操作没有产生任何效果
    【线程A】执行wait() 操作, 进入等待状态,如果没有额外的 notify() 操作, 该线程将持续在 condition = true 的情形下, 持续处于等待状态得不到执行。

    2、为什么wait()一定要放在循环里??
    多线程中,wait()的标准使用方法:

    synchronized (monitor) {
        //  判断条件谓词是否得到满足
        while(!locked) {
            //  等待唤醒
            monitor.wait();
        }
        //  处理其他的业务逻辑
    }
    

    若是使用简单的判断,如下所示:

    synchronized (monitor) {
        //  判断条件谓词是否得到满足
        if(!locked) {
            //  等待唤醒
            monitor.wait();
        }
        //  处理其他的业务逻辑
    }
    
    
    

    出现的问题:
    睡眠的线程被唤醒之后有可能不满足while()中的条件判定,使用if不是很准确。详情参考下面的代码,当site发生变化的时候,km并没有发生变化。

    /*
    需求:
    App有两个属性,site和km,当这两个属性其中一个发生变化的时候
    需要进行输出,没有内容发生变化的时候就不发生变化
     */
    public class App {
        public String CITY = "shanghai";
        public String site = "shanghai";
        public int km=0;
    
    
        public App() {
    
        }
    
    
        /*
        地址发生变化。进行通知
         */
        public synchronized void changeSite(String city) {
            this.site = city;
            notifyAll();
    
        }
    
        /*
        里程数发生变化就进行通知
         */
        public synchronized void changeKm() {
            km = 101;
            notifyAll();//只要有变化就进行通知
        }
    
        /*
        一直进行等待地址的改变
         */
        public  synchronized void waitSite() {
            while(CITY.equals(this.site)) {
                try {
                    wait();
                    System.out.println(Thread.currentThread().getId()+" is waiting for site change~");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
    
            System.out.println(Thread.currentThread().getName()+" has changed~");
        }
    
    
    
    
    
        /*
        一直进行等待里程数的改变
         */
        public synchronized void waitKm() {
            while(this.km<100) {
                try {
                    wait();
                    System.out.println(Thread.currentThread().getId()+" is smaller than 100 km");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
    
            System.out.println(Thread.currentThread().getName()+" is bigger than 100 km");
        }
    
        /*
        负责等待的线程
         */
        class WaitSiteThread extends Thread {
    
            @Override
            public void run() {
                waitSite();
            }
        }
        class WaitKmThread extends Thread {
    
            @Override
            public void run() {
                waitKm();
            }
        }
    
    
    
        @Test
        public void test() {
    
            //启动三个进行等待的线程
    
            for (int i = 0; i < 3; i++) {
                new WaitSiteThread().start();
            }
            for (int i = 0; i < 3; i++) {
                new WaitKmThread().start();
            }
    
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            changeSite("beijing");
    
        }
    
    
    

    3、是谁在调用wait()和notify()??
    被加锁的对象在调用wait()和notify()。
    加锁的对象调用 wait() 方法后,线程进入等待状态,直到在加锁的对象上调用 notify() 或者 notifyAll() 方法来唤醒之前进入等待的线程

    4、notify()之后会不会释放锁呢?
    不会释放锁,一直到执行的方法完成之后才释放锁。
    测试方法:
    在notify()后面加上睡眠时间。到时间之后才会释放锁。

    参考链接:https://blog.csdn.net/lengxiao1993/article/details/52296220

    相关文章

      网友评论

          本文标题:关于wait()方法的使用

          本文链接:https://www.haomeiwen.com/subject/cmhnactx.html