1、wait和notify
由于线程之间是抢占式执行的,所以线程之间的执行先后顺序难以预知。但实际上是希望合理的协调多个线程之间的执行先后顺序。
完成这个协调工作,主要涉及到三个方法
*wait()/wait(long timeout);让当前线程进入等待状态。
*notify()/notifyAll();唤醒在当前对象上等待的线程。
注意:wait,notify,notifyAll都是Object的方法,而之前提到的join()(等待当前线程运行结束)方法是Thread类中的方法,
2、wait方法
wait做的事情:
*使当前执行的代码的线程进行等待。(把线程放到等待队列中)
*释放当前锁
*满足一定条件就会被唤醒,重新尝试获取这个锁。
wait要搭配synchronized一起使用,脱离synchronized使用wait就会抛出异常。
wait结束等待的条件:
*其他线程调用该对象的notify()方法
*wait等待时间超时(wait提供一个带有timeout参数的版本,来指定等待时间)
*其他线程调用该等待线程的interrupted方法,导致wait抛出InterrputedException异常。
3、 notify方法
notify是唤醒等待线程的方法
*方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其他线程,对其发出通知notify(),并使它们重新获取该对象的对象锁。
*如果有多个线程等待,则有线程调度器随机挑选一个状态为wait的线程,(并没有“先来后到的原则”)。
*在notify()方法后,当前线程不会马上释放该对象锁,要等待到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。
4、代码示例:
/**
* wait()和notify()方法
*/
public class Exe_02 {
public static void main(String[] args) {
//定义一个锁对象
Object locker=new Object();
//创建调用wait()方法的线程
Thread t1=new Thread(() ->{
while(true){
System.out.println("wait之前");
try {
synchronized (locker) {
locker.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait之后");
System.out.println("==============");
}
},"t1");
//创建调用notify方法线程
Thread t2=new Thread(() ->{
while(true){
System.out.println("notify之前");
//加入锁
synchronized (locker) {
locker.notify();
}
System.out.println("notify之后");
//休眠一会
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t2");
//启动线程
t1.start();
t2.start();
}
}
执行逻辑分析:
注意:
1、当一个线程调用了wait()之后,就释放掉当前持有的锁,等待被其他线程唤醒。
2、当另一个线程调用了notify()之后, 之前调用wait()的线程被唤醒后,需要重新竞争锁资源然后再从之前wait的位置向下执行自己的逻辑。
4.1、notify()和notifyAll()
notify方法只是随机唤醒某一个线程,这个线程来获取锁;
notifyAll可以一次性唤醒所有等待的线程,这些线程全部去竞争锁,谁先拿到谁先处理。
5、观察多线程环境下锁状态
代码示例:
import org.openjdk.jol.info.ClassLayout;
public class Exe_03 {
//定义一些变量
private int count;
private long count1=200;
private String hello="";
//定义一个对象变量
private textExe_03 text03=new textExe_03();
public static void main(String[] args) throws InterruptedException {
//创建一个对象的实例
Object obj=new Object();
//打印实例布局
System.out.println("=====任意object对象布局,起初无锁状态");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
System.out.println("延迟三秒开启偏向锁");
//延迟3秒开启偏向锁
Thread.sleep(3000);
//创建本类的实例
Exe_03 exe_03=new Exe_03();
//打印实例布局,查看锁状态
System.out.println("=====打印实例布局,查看锁状态");
System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
//调用hashCode后,保存hashCode的值
exe_03.hashCode();
//观察现象
System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
System.out.println("==============================");
System.out.println("synchronized加锁");
//加锁后观察锁信息
synchronized(exe_03){
System.out.println("第一层synchronized加锁后");
System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
//锁重入,观察锁信息
synchronized(exe_03){
System.out.println("第二层synchronized加锁后");
System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
}
//释放里层的锁
System.out.println("释放内层锁后");
System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
}
//释放所有锁之后
System.out.println("=========释放所有锁========");
System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
System.out.println("==============================");
//强制执行垃圾回收
System.gc();
//观察GC计数
System.out.println("+++++++调用GC后查看age的值");
System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
//打印类布局,调用不同的方法查看
System.out.println("+++++查看类布局");
System.out.println(ClassLayout.parseClass(Exe_03.class).toPrintable());
//打印类对象布局
System.out.println("+++++查看类对象布局");
System.out.println(ClassLayout.parseInstance(Exe_03.class).toPrintable());
synchronized (Exe_03.class){
//加锁后的类对象
System.out.println("+++++对类对象加锁后,不同的对象获取锁,观察锁升级为thin lock");
System.out.println(ClassLayout.parseInstance(Exe_03.class).toPrintable());
}
//释放锁之后的类对象
System.out.println("+++++释放锁后");
System.out.println(ClassLayout.parseInstance(Exe_03.class).toPrintable());
System.out.println("+++++多个锁线程参与锁竞争,观察锁状态+++++");
Thread t1=new Thread(() ->{
synchronized(exe_03){
System.out.println("++++++在线程A中参与锁竞争,观察锁状态++++++");
System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
}
});
t1.start();
Thread t2=new Thread(() ->{
synchronized(exe_03){
System.out.println("++++++在线程B中参与锁竞争,观察锁状态++++++");
System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
}
});
t2.start();
Thread t3=new Thread(() ->{
synchronized(exe_03){
System.out.println("++++++在线程C中参与锁竞争,观察锁状态++++++");
System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
}
});
t3.start();
}
}
class textExe_03{
}
查看运行结果:
文章来源:https://www.toymoban.com/news/detail-498495.html
文章来源地址https://www.toymoban.com/news/detail-498495.html
到了这里,关于多线程中的wait和notify的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!