java等待和通知

wait() , notify() 和 notifyAll()的使用。

1、java等待和通知标准的公式

   等待方

    1)获取对象锁

    2)在循环中判断条件是否满足,不满足wait(), 满足执行具体业务逻辑代码

 

   通知方

    1)获取对象锁

    2)  更改判断条件,通知所有等待线程,调用notifyAll()

 

   下面是围绕着这个标准公式编写的案例代码(实现1个窗口打饭的操作)

   

​
public class Main2 {

    //数组中值为0的窗口没有人打饭
    private volatile Integer[] windows = new Integer[1];

    public Main2(){
        windows[0] = 0;
    }

    /**
     * 等待方
     */
    private  void com() throws InterruptedException {
        synchronized (windows) {
            while (windows[0] != 0) {
                //当数组中没有0时,等待
                System.out.println("有人在打饭,请线程[" + Thread.currentThread().getId() + "]稍等片刻!");
                windows.wait();
            }


            windows[0] = 1;
            System.out.println("线程[" + Thread.currentThread().getId() + "]可以打饭了!");
        }
    }



    /**
     * 通知方
     */
    private void back() throws InterruptedException {
        synchronized (windows) {
            windows[0] = 0;
            windows.notifyAll();
        }
    }


    public static void main(String[] args) throws InterruptedException {
        Main2 m = new Main2();

        for(int i=0 ; i<5;i++) {
            new Thread(() -> {
                try {
                    m.com();
                    Thread.sleep(1000);
                    m.back();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

    }

}

​

 

运行结果如下

 

 通过以上一个案例,我们可以得到如下几个结论:

    1)wait() , notify() , notifyAll()方法都必须在由synchronized修饰的同步方法或者同步代码块中使用才可以,否则会抛出java.lang.IllegalMonitorStateException异常。

    2)wait()和 sleep()的区别

          wait():Object类自带方法,表示将当前线程加入到等待池中,释放当前线程持有的锁,供其他线程进入同步代码块。

          sleep() : Thread类的静态方法,功能仅仅是单纯的让当前线程休眠一段时间,不会持有对象锁,更不会释放对象锁,它会持有cpu资源。

    3)notify()方法和notifyAll()的区别

          notify(): 当同时有多个线程处于同一个锁的等待池中,如果调用了该方法,则会随机抽取其中一个线程进行通知。

          notifyAll() :  和notify()方法类似,不同的是在通知时,它会通知锁的等待池中所有的线程。

          综合考虑,许多情况下通知的线程可能是需要指定的线程,调用notify()随机通知的线程可能并不是我们需要通知的线程,            所以使用notifyAll()更好一点。

       

很多情况下,线程等待不可能无限制的等待下去,wait(long time)可以设置等待时间,下面是针对上面打饭案例的设置等待时间的案例

 

​
public class Main2 {

    //数组中值为0的窗口没有人打饭
    private volatile Integer[] windows = new Integer[1];

    public Main2(){
        windows[0] = 0;
    }

    /**
     * 等待方
     */
    private  void com() throws InterruptedException {
        synchronized (windows) {
            long overTime = System.currentTimeMillis() + 1000;
            long waitTime = 1000;
            while (windows[0] != 0) {
                if(waitTime>0){
                    //当数组中没有0时,等待
                    System.out.println("有人在打饭,请线程[" + Thread.currentThread().getId() + "]稍等片刻!");
                    windows.wait(1000);
                }else{
                    System.out.println("等待时间太长了!线程["+Thread.currentThread().getId()+"] 不等了,离开!");
                    return;
                }
                waitTime = overTime-System.currentTimeMillis();
            }

            windows[0] = 1;
            System.out.println("线程[" + Thread.currentThread().getId() + "]可以打饭了!");
        }
    }



    /**
     * 通知方
     */
    private void back() throws InterruptedException {
        synchronized (windows) {
            windows[0] = 0;
            windows.notifyAll();
        }
    }


    public static void main(String[] args) throws InterruptedException {
        Main2 m = new Main2();

        for(int i=0 ; i<5;i++) {
            new Thread(() -> {
                try {
                    m.com();
                    Thread.sleep(1000);
                    m.back();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

    }

}

​

 

运行结果如下

 

        

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值