什么是线程(下篇)

什么是线程(下篇)

wait 和 notify

由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知.但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序.

完成这个协调工作, 主要涉及到三个方法
wait() / wait(long timeout): 让当前线程进入等待状态.
notify() / notifyAll(): 唤醒在当前对象中等待的线程.
注意: wait, notify, notifyAll 都是 Object 类的方法.

wait()方法

wait做了三件事:
1.让当前正在执行代码的线程进行阻塞等待. (让这个线程的PCB从就绪队列切换到等待对列中)并随时准备接受通知.
2.释放当前锁、(要想使用wait/notify ,必须搭配synchronized . 需要先获取到锁,才有资格谈wait.)释放当前锁是为了后续的线程更好的去竞争这把锁的资源
3.满足一定的条件被唤醒时, 重新尝试获取到这个锁.
注意: 其中1和2是要原子的完成,而且wait 要搭配 synchronized 来使用. 脱离 synchronized 使用 wait 会直接抛出异常.

wait 结束等待的条件:
1)其他线程调用该对象的 notify 方法.

解释:waitnotify都是Object的方法.比如线程1中的对象1调用了wait.必须要有个线程2 .也调用对象线程1notify, 才能唤醒线程1.如果是线程2,调用了对象2的notifiy,就无法唤醒线程1 .

2)wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).
3)其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常.

public class ThreadDemo18 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Object object = new Object();
        synchronized (object){
    
    
            System.out.println("wait之前!");
            object.wait();
            System.out.println("wait之后!");
        }
    }
}
//运行结果:
//wait之前!

在这里插入图片描述

notify()方法

notify方法只是唤醒某一个等待线程. 使用notifyAll方法可以一次唤醒所有的等待线程.

1)也要放到synchronized中使用 该方法是用来通知那些可能等待该对象的对象锁的
其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁

2)notify操作是一次唤醒一个线程.如果有多个线程都在等待中,调用notify相当于随机唤醒了一个.其他线程仍保持原状.(并没有 "先来后到")
3)调用notify这是通知对方被唤醒,但是调用notify本身的线程并不是立即释放锁,而是要等待当前的synchronized代码块执行完才能释放锁.(notify本身不会释放锁)

/**
 * notify
 */
public class ThreadDemo19 {
    
    
    static class WaitTask implements Runnable{
    
    
        private Object locker = null;

        public WaitTask(Object locker) {
    
    
            this.locker = locker;
        }

        @Override
        public void run() {
    
    
            //进行wait()线程
            synchronized (locker){
    
    
                System.out.println("wait开始!");
                try {
    
    
                    locker.wait();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                System.out.println("wait 结束!");
            }
        }
    }

    static class NotifyTask implements Runnable{
    
    
        private Object locker = null;

        public NotifyTask(Object locker) {
    
    
            this.locker = locker;
        }

        @Override
        public void run() {
    
    
            //进行notify()线程
            synchronized (locker){
    
    
                System.out.println("notify开始!");
                //一次只能唤醒一个
                //locker.notify();
                //全部唤醒
                locker.notifyAll();
                System.out.println("notify结束!");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        //因为WaitTask()和NotifyTask()是两个类,不好调用
        //可以新建一个对象,去专门负责调用
        Object locker = new Object();
        Thread t10 = new Thread(new WaitTask(locker));
        Thread t11 = new Thread(new WaitTask(locker));
        Thread t2 = new Thread(new NotifyTask(locker));
        t10.start();
        t11.start();
        Thread.sleep(3000);
        t2.start();
    }
}

wait 和 sleep 的对比(面试题)

其实理论上 waitsleep 完全是没有可比性的,因为一个是用于线程之间的通信的,一个只是让线程阻塞一段时间,(其实没有明确的关联关系.)
唯一的相同点就是都可以让线程放弃执行一段时间.当然为了面试的目的,我们还是总结下:

  1. wait 需要搭配 synchronized 使用. sleep 不需要.
  2. waitObject 的方法 sleepThread 的静态方法.
  3. sleep操作是指定一个固定时间来阻塞等待. wait的话既可以指定时间,也可以无限等待.
  4. wait唤醒可以通过notify或者interrupt 或者时间到来唤醒, sleep唤醒通过时间到或者interrupt唤醒.的静态方法.
  5. wait主要的用途就是为了协调线程之间的先后顺序这样的场景并不适合使用sleep . sleep单纯让该线程休眠并不涉及到多个线程的配合.

猜你喜欢

转载自blog.csdn.net/TuttuYYDS/article/details/125340481