网站备案 换域名,云南楚雄旅游必去的景点,开发网站公司的简介,网站开发是先做前段还是后台目录
一、概念
二、用法
#xff08;1#xff09;举个栗子#xff1a;
#xff08;2#xff09;wait和notify的使用
1、没有上锁的wait
2、当一个线程被wait#xff0c;但没有其他线程notify来释放这个wait
3、两个线程#xff0c;有一个线程wait#xff0c;有一…目录
一、概念
二、用法
1举个栗子
2wait和notify的使用
1、没有上锁的wait
2、当一个线程被wait但没有其他线程notify来释放这个wait
3、两个线程有一个线程wait有一个线程notify来释放wait
4、notifyAll
3wait的三个选项
三、wait、sleep、join 一、概念
我们知道多线程在系统中的调度是随机的我们不能干预多个线程的执行顺序但是我们可以使某个线程放弃被系统调用让其他线程先被调用这样可以达到我们的预期效果
wait就是让多线程进行锁竞争的时候让后执行的线程放弃和别的线程进行锁竞争别的线程执行完后别的线程使用notify将wait的线程不想进行锁竞争这个信息释放掉再次和其他线程锁竞争。等待通知的机制和join用途类似 二、用法
1举个栗子 现在有很多滑稽老铁要去ATM里滑稽A是取钱的滑稽B是存钱的滑稽C是运钞票的人员负责给ATM机补充钱防止ATM机没钱了别人取不到钱。而这里的滑稽A滑稽B滑稽C我们当做是线程每次去ATM机里只能有一个人进去相当于上锁了其他人不能进去等ATM机里面的人完成操作后出来后别的人才能进去但是这里是多线程的原因其他线程会有锁竞争。 当A进去ATM机里后就上锁其他人不能进去如图 把滑稽A比作是线程当A线程进去后就会上锁A线程要进行取钱的操作其他线程不能进去操作当A线程执行完自己的操作后其他线程才能去锁竞争。 但是如果ATM机里面没有钱时A线程就不能完成取钱这个操作它会退出ATM机但退出后呢它因为没有完成取钱的操作就会想继续进去ATM里面完成取钱这个操作就会继续和其他线程进行锁竞争因为A线程拿到了锁处于RUNNABLE状态其他线程因为阻塞处于BLOCKED状态需要被系统唤醒后才能去竞争锁但是线程A呢不用唤醒就能去竞争锁后面又被A线程拿到锁的可能性还是很大的类似近水楼台先得月。如果这样子那线程A频繁的进去又出来干不了事但是其他线程也不能进去操作用通俗的话说就是占着茅坑不拉屎的意思。也就出现线程安全问题了。其他线程无法拿到锁这个情况称为 “线程饿死”。 这里的线程A的代码大概逻辑是这样的 当A线程没有取到钱就会一直重复加锁解锁的操作。 这样的bug没有死锁那么严重但也是要解决的。那如何解决呢。这时就可以用wait和notify了。期望改进成如下图 这里的wait内部做了三件事 1释放锁给其他线程竞争锁 2进入阻塞等待 3等其他线程使用notify后解除wait参与到锁竞争中 2wait和notify的使用
wait的使用前提必须是当前对象被上锁了才能使用不能你对象没被上锁就wait了那也不知道是在wait谁。同时有线程wait了也必须有其他线程notify来释放这个wait不然这个wait就会一直阻塞。
1、没有上锁的wait 代码 public class TestDemo1 {public static void main(String[] args) throws InterruptedException {Object locker new Object();locker.wait();}
} 执行结果 2、当一个线程被wait但没有其他线程notify来释放这个wait 代码 public class TestDemo3 {public static void main(String[] args) {Object locker new Object();Thread t1 new Thread(() - {synchronized (locker) {System.out.println(wait之前);try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(wait之后);}});t1.start();}
}执行结果 打印不了 “wait之后”一直是阻塞等待状态在jconsole中状态如图 3、两个线程有一个线程wait有一个线程notify来释放wait 代码 public class TestDemo2 {public static void main(String[] args) {Object locker new Object();Thread t1 new Thread(() - {synchronized (locker) {System.out.println(t1 wait之前);try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(t2 wait之后);}});Thread t2 new Thread(() - {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (locker) {System.out.println(t2 notify之前);locker.notify();System.out.println(t2 notify之后);}});t1.start();t2.start();}
}注意这里的释放wait的notify用的对象必须是要一样的如果不一样wait是不能被释放的t1也就不能被唤醒了. 在系统中notify可以不用上锁但是在java中规定了要上锁而且上锁的对象也要和notify对象一样所以和系统是有区别的。 执行结果 结果解析 t1 和 t2 执行的时候 1因为t1 sleep了1秒所以能保证t1 先wait所以先打印 “t1 wait之前”这时t1就进入阻塞等待状态。 2t2线程sleep了1秒后获得这个locker锁打印“t2 notify 之前”当t2线程执行了notify后t1 线程的wait就被释放了。 3因为t2还在持有锁所以t1会还会进入阻塞t2打印 “t2 notify之后” 释放锁。 4t1拿到锁再打印“t1 wait之后”。 4、notifyAll
唤醒等待这个对象的所有线程假设有很多个线程都使用同一个对象wait这时使用notifyAll所有使用了这个对象的wait的线程都会被唤醒。
注意当这些线程都被唤醒时就要重新获取锁他们还是要进行锁竞争的这里也就相当于串行执行了线程调度还是随机调度的。而且使用notifyAll后全部使用同一对象wait的线程都被唤醒了不好控制更加推荐使用notify。
3wait的三个选项 如图 没有参数的就是死等但是很多情况死等是不合理的所以我们加参数就是让某个线程在一定时间wait如果超出了这个时间就不wait了直接过掉wait。 有一个参数的精确范围是毫秒级别两个参数的精确范围是纳秒级别。 三、wait、sleep、join
wait需要搭配synchronized使用线程wait时处于WAITING状态需要其他线程notify后才能被唤醒或者设置时间到时就唤醒可以兜底。
sleep线程sleep时要到一定休眠时间才能被唤醒但是也能被interrupt终止但是这种情况是会抛异常的是非常规手段不符合我们预期的效果。
join啥线程调用join当前线程就要等啥线程执行完才能之前当前线程和wait一样有参数可以选择到时就不等了。