高并发(6)- 多线程之间的协作
@[TOC](高并发(6)- 多线程之间的协作)
前言
上篇文章讲解了线程之间的共享。本篇文章就来讲讲线程之间的协作。
毕竟java线程是协作式,而非抢占式的。
线程的协作
一、什么是线程的协作
顾名思义,线程的协作就是多个线程之间的协作。比如快递这个场景,一个线程负责处理快递的物流信息更新,什么时候快递到了什么的地区,一个线程负责快递的事实信息,当快递到了某个地点,这个时候通知负责物流更新的线程物流进度有变化,你快更新,这个就是线程的协作。
二、线程协作方式
wait、notify、notifyAll三种方法来实现,分别是等待,唤醒和全部唤醒方法。
1.waiti
wait是等待方法,执行wait方法会释放当前锁,让出cpu,进入等待状态。只要notify/notifyAll()方法被执行的时候,才会唤醒一个或多个正处于等待的线程,然后继续往下执行,执行完synchronized 代码块的或者遇到了wait的时候,会再次释放锁。
2.notify
notify是唤醒方法,可以唤醒当前线程,从wait状态回到就绪状态,重新参与cpu的抢夺之中。
3.notifyAll
notifyAll也是唤醒方法,但唤醒的是所有线程,使所有的wait状态的线程重新回到就到就绪状态,同样参与cpu的争夺。
三、代码
/**
* @version 1.0
* @Description 快递对象
* @Author wb.yang
*/
public class Express {
public final static String CITY = "HeNan";
/**
* 快递地址
*/
private String site;
public Express(String site) {
this.site = site;
}
/**
* 地点数有变化的时候,通知处于wait状态的,进行公里变化的业务处理
*/
public synchronized void changeSite() {
this.site = "BeiJing";
notifyAll();
}
public synchronized void waitSite() {
while (CITY.equals(this.site)) {
try {
System.out.println("检查地点线程[" + Thread.currentThread().getId()
+ "] 等待中");
wait();
System.out.println("检查地点线程[" + Thread.currentThread().getId()
+ "] 被通知了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前地点是" + this.site + "我要通知用户");
}
}
上面的代码可以看出,我们定义了一个快递的对象,包含了快递当前地点,还有一个等待地点变化的方法,在本方法中等待地点变化,实行我们的业务逻辑,然后有一个变化地点的方法,变换快递地点并调用notifyAll方法,唤醒等待的线程。
/**
* @version 1.0
* @Description 线程协作demo
* @Author wb.yang
*/
public class SynergyDemo {
private static Express express = new Express(Express.CITY);
private static class CheckSite extends Thread {
@Override
public void run() {
express.waitSite();
}
}
public static void main(String[] args) throws InterruptedException {
new CheckSite().start();
Thread.sleep(5000);
//快递地点更新
System.out.println("快递地点更新");
express.changeSite();
}
}
这个代码是我们执行线程的方法,main方法中,先运行了线程的run方法,进行快递地点变化的等待,然后休眠五秒后,调用快递地点变化的方法,唤醒等待的线程,执行接下来物流更新的逻辑。
代码运行结果
从结果中可以看出,先是线程检查地点,然后进入等待中,随后开始更新快递地点,然后线程结束等待,输出最新的物流信息。
四、总结
通过使用wait方法使线程进入等待状态,然后释放锁,让出cpu,通过notify和notifyAll来唤醒线程,是等待状态重新变为就绪状态,开始抢夺cpu,然后执行业务逻辑。