1.wait()和notify()方法
由于线程调度是抢占式执行的,因此线程的执行顺序难以预知.
但实际开发中有时候我们希望合理的协调多个线程之间的执行顺序.
要做到这一点我们需要wait(),notify(),notifyAll()这几个方法来协助完成.
wait()/wait(long timeout):让当前线程进入等待状态.
notify()/notifyAll():唤醒在当前对象上等待的线程.
wait,notify,notifyAll都在Object类的方法.
1wait()方法
wait方法做的事情:
1.释放当前锁.
2.使当前执行代码的线程进行等待,进入当前该锁对象的等待集合中.
3.当其他线程调用notify的时候,wait解除阻塞,并重新获取到锁.
wait方法需要在synchronized方法中调用,脱离synchronized调用wait会直接抛出异常.
调用wait的对象,必须和synchronized中的锁对象使一致的.
因此,wait解锁解的是synchronized中的锁对象.
wait被唤醒后,重新获取锁当然也是synchronized中的锁对象.
只有和wait中synchronized中相同的锁对象调用notify才能唤醒调用wait的线程.
wait等待结束的条件
1.其他线程调用该对象的notify方法.
2.wait等待时间超时(wait方法提供了一个带有timeout参数的版本,来指定等待时间).
3.其他线程调用interrupt方法,导致wait超出InterruptedException异常
使用案例
public static void main(String[] args) throws InterruptedException {
Object locker = new Object();
synchronized (locker) {
System.out.println("等待中");
locker.wait();
System.out.println("等待结束");
}
}

没有notify方法唤醒就会一直等待下去.
2.notify()方法
notify()方法是唤醒等待的线程
notify()方法也要在同步方法或同步代码块中使用,该方法是通知那些可能等待该对象的对象锁的其他线程,对其发出通知notify,并使它们重新获取该对象的对象锁.
如果有多个对象等待,则由线程调度器随机挑选出一个呈wait状态的线程.(并没有先来后到)
在notify()方法之后,当前线程不会立刻释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁.
代码案例
public class Test_2 {
private static Object locker = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
synchronized (locker) {
System.out.println("t1等待中");
try {
locker.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
locker.notify();
System.out.println("t1结束等待");
}
});
Thread t2 = new Thread(()->{
synchronized (locker) {
System.out.println("t2等待中");
locker.notify();
try {
locker.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("t2结束等待");
}
});
t1.start();
Thread.sleep(1000);
t2.start();
}
}

3.notifyAll()方法
notify()方法只是唤醒一个等待线程.而notifyAll()方法是一次性唤醒所有等待线程.
notifyAll()唤醒的线程不是所有的线程都会开始执行,而是都进入就绪状态要一起竞争锁对象,只有获取到锁对象的线程才能继续执行,其他线程会继续阻塞等待锁的释放.
代码案例
package blogs;
public class Test_2 {
private static Object locker = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
synchronized (locker) {
System.out.println("t1等待中");
try {
locker.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("t1结束等待");
}
});
Thread t2 = new Thread(()->{
synchronized (locker) {
System.out.println("t2等待中");
try {
locker.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("t2结束等待");
}
});
Thread t3 = new Thread(()->{
synchronized (locker) {
System.out.println("t3等待中");
try {
locker.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("t3结束等待");
}
});
Thread t4 = new Thread(()->{
synchronized (locker) {
System.out.println("唤醒所有线程");
locker.notifyAll();
}
});
t1.start();
t2.start();
t3.start();
Thread.sleep(1000);
t4.start();
}
}

2.wait和sleep的区别
其实wait和sleep完全没有可比性,wait()是线程中的通信机制,用于线程中的同步和协调,而sleep只是简单的让当前线程暂停执行一段时间.
唯一的相同点就是会让线程放弃执行一会.
1.wait需要搭配synchronized使用,sleep不需要.
2.wait是属于Object类的方法,sleep是属于Thread类的方法.
3.wait会释放当前线程对象锁以便其他线程获取,进行阻塞等待,而sleep不会释放当前线程对象锁而是直接进入阻塞等待.
4.wait可以超时唤醒,也可以被拥有相同锁对象的其他线程调用notify()方法唤醒,sleep只会在超时唤醒,两者都可以在等待休眠期被其他线程调用Interrupt方法提前唤醒.
本文介绍了Java中wait(),notify(),notifyAll()方法在多线程协调中的作用,包括它们的使用场景、规则和区别于sleep的方法。重点强调了这些方法在同步控制中的重要性以及如何确保线程间的正确交互。

1万+

被折叠的 条评论
为什么被折叠?



