什么是线程通信、如何实现?
- 所谓线程通信就是线程间相互发送数据,线程间共享一个资源即可实现线程通信。
线程通信常见形式
- 通过共享一个数据的方式实现。
- 根据共享数据的情况决定自己该怎么做,以及通知其他线程怎么做
线程通信实际应用场景
- 生产者与消费者模型:生产者线程负责生产数据,消费者线程负责消费生产者产生的数据。
- 要求:生产者线程生产完数据后唤醒消费者,然后等待自己,消费者消费完该数据后唤醒生产者,然后等待自己。
线程通信案例模拟
- 模拟客服系统,系统可以不断的接入电话 和 分发给客服。
线程通信的前提:
线程通信通常是在多个线程操作同一个共享资源的时候需要进行通信,且要保证线程安全。
Object类的等待和唤醒方法:
注意:
- 上述方法应该使用当前同步锁对象进行调用(实例方法使用this作为锁,所以用
this
调用)。
线程通信的三个常见方法
注意:
- 上述方法应该使用当前同步锁对象进行调用,因为只有锁对象才知道谁在用我,我要等待谁。
代码如下:
/*注意:五个人用的是同一个账户,五个人都要修改账户,默认只能一个人修改,
所以五个人用的是同一把锁,用的都是this(当前账户)*/
public class Account {
private String cardId;
private double money;//账户的余额
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public Account(String cardId, double money) {
this.cardId = cardId;
this.money = money;
}
public Account() {
}
/**
* 存钱
* @param money
*/
public synchronized void deposit(double money) {
try {
//得到谁来存钱
String name = Thread.currentThread().getName();
if (this.money == 0){
//没钱了:需要存钱
this.money += money;
System.out.println(name+"存钱"+money+"成功,余额是:"+this.money);
this.notifyAll();
this.wait();
}else {
//有钱:不需要存钱,唤醒别人,等待自己即可
this.notifyAll();//唤醒所有线程
this.wait();//锁对象,让当前线程进入等待
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 小明和小红不断的取钱,每隔3秒取一次
* @param money
*/
public synchronized void drawMoney(double money) {
try {
//得到谁来取钱
String name = Thread.currentThread().getName();
//判断钱够不够
if (this.money >= money){
this.money -= money;
System.out.println(name+"来取钱"+money+"成功,余额是"+this.money);
//没钱了
this.notifyAll();//唤醒所有线程
this.wait();//锁对象,让当前线程进入等待
}else {
//钱不够
//没有数据消费,应该唤醒别人,等待自己(将cpu让出)
//先把别人叫醒,自己再去睡觉
this.notifyAll();
this.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 取钱的线程类(用这个创建两个取钱线程对象)
*/
public class DrawThread extends Thread{
//接收处理的账户对象
private Account acc;
public DrawThread(Account acc, String name){
super(name);
this.acc = acc;
}
@Override
public void run() {
//小明和小红各自调用run方法来 取钱的
while (true) {
acc.drawMoney(100000);
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 取钱的线程类(用这个创建两个取钱线程对象)
*/
public class DepositThread extends Thread{
//接收处理的账户对象
private Account acc;
public DepositThread(Account acc, String name){
super(name);
this.acc = acc;
}
@Override
public void run() {
//亲爹,干爹,岳父 存钱的
while (true) {
acc.deposit(100000);
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//目标:了解线程通信的流程
//使用三个爸爸存钱,2个孩子取钱,模拟线程通信思想(一存 一取)
//1、创建账户对象,代表5个人共同操作的账户(通过同一个账户通信)
Account account = new Account("ICBC-1123",0);
//2、创建两个取钱线程,代表小明和小红
new DrawThread(account,"小明").start();
new DrawThread(account,"小红").start();
//3、创建三个存钱线程,代表三个爸爸(亲爹,干爹,岳父)
new DepositThread(account,"亲爹").start();
new DepositThread(account,"干爹").start();
new DepositThread(account,"岳父").start();
}
}