java线程的等待和唤醒

一.基础知识

java有一句话叫做一切皆对象,这个最基本的对象就是object;在object中,定义了几个和线程相关的方法,如下:

  • notify() :唤醒在此对象监视器上等待的单个线程。
  • notifyAll() : 唤醒在此对象监视器上等待的所有线程。
  • wait():让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
  • wait(long timeout) : 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。注意:如果其他线程一直占有对象锁,则该方法不会生效,会等到对象锁不被占用的时候才会被自动唤醒
  • wait(long timeout, int nanos)  -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。

注意:

  • 上述五个方法都必须在拥有对应对象的同步锁,否则会抛出  IllegalMonitorStateException异常,表示调用该方法的线程没有对应对象的锁,却调用了这些方法;
  • 主线程使用的等待锁和子线程使用的唤醒锁必须是同一把同步锁,否则子线程使用的同步锁唤醒的线程和主线程不是同一个线程

二.案例

  1. 使用wait()和notify()结合,主线程启动子子线程后,进入等待状态,等待子线程唤醒
/**
 * 主线程:测试线程和唤醒
 */
public  static void main(String[] arg){
    log.info(">>>>>主线程执行");

    MyThread myThread = new MyThread("线程1",lock);
    log.info(">>>>>主线程启动子线程");
    myThread.start();

    synchronized (lock){

        long startTime = System.currentTimeMillis();
        try {
            lock.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        log.info(">>>>>主线程等待子线程时间:{}",endTime - startTime);
        log.info(">>>>>主线程继续执行");
    }
}
/**
 * 子线程:测试线程和唤醒
 */
public void run(){
    log.info(">>>>>子线程【{}】开始执行,延时1s",name);
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    //如果把业务代码块也整合到同步代块内,会导致该子线程会一直占用lock锁,
    //导致主线程无法获取lock的对象锁,所以主线程设置lock.wait(2000)5S超时会无效,实际会等到子线程运行结束主线程才会被唤醒
    synchronized (lock){
        log.info(">>>>>子线程执行结束,唤醒主线程");
        //wait和notify等方法必须拥有的对象锁,否则会抛出 IllegalMonitorStateException异常,
        // 表示当前线程没有拥有该对象锁,却调用过了wait和notify等方法
        //唤醒主线程
        lock.notify();
    }
}

结果如图所示:主线程等到子线程结束唤醒后才继续执行剩余的流程

使用wait()和notify()结合,主线程启动子子线程后,进入等待状态,等待子线程唤醒

    2.使用wait(long timeout)和notify()结合,主线程等待最长时间不超过5s的时间,超过则自动唤醒,代码如下

/**
 * 主线程:测试线程和唤醒
 */
public  static void main(String[] arg){
    log.info(">>>>>主线程执行");

    MyThread myThread = new MyThread("线程1",lock);
    log.info(">>>>>主线程启动子线程");
    myThread.start();

    synchronized (lock){

        long startTime = System.currentTimeMillis();
        try {
            lock.wait(2000);//主线程设置最长等待时间为2s,超过则自动唤醒,不依赖子线程唤醒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        log.info(">>>>>主线程等待子线程时间:{}",endTime - startTime);
        log.info(">>>>>主线程继续执行");
    }
}
/**
 * 子线程:测试线程和唤醒
 */
public void run(){
    log.info(">>>>>子线程【{}】开始执行,延时1s",name);
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    //如果把业务代码块也整合到同步代块内,会导致该子线程会一直占用lock锁,
    //导致主线程无法获取lock的对象锁,所以主线程设置lock.wait(2000)5S超时会无效,实际会等到子线程运行结束主线程才会被唤醒
    synchronized (lock){
        log.info(">>>>>子线程执行结束,唤醒主线程");
        //wait和notify等方法必须拥有的对象锁,否则会抛出 IllegalMonitorStateException异常,
        // 表示当前线程没有拥有该对象锁,却调用过了wait和notify等方法
        //唤醒主线程
        lock.notify();
    }
}

结果如图所示:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值