线程通信(了解)
一、概述
- 所谓线程通信就是线程间相互发送数据,线程通信通常通过共享一个数据的方式实现。
- 线程间会根据共享数据的情况决定自己该怎么做,以及通知其他线程怎么做。
二、常见模型
- 生产者与消费者模型:生产者线程负责生产数据,消费者线程负责消费数据。
- 要求:
- 生产者线程生产完数据后,唤醒消费者,然后等待自己;
- 消费者消费完该数据后,唤醒生产者,然后等待自己。
三、案例模拟
1、场景
-
假如有这样一个场景:
-
小明和小红有三个爸爸,爸爸们负责存钱;
-
小明和小红负责取钱,必须一存、一取。
-
-
线程通信的前提:线程通信通常是在多个线程操作同一个共享资源的时候需要进行通信,且要保证线程安全。
2、Object类的等待和唤醒方法:
方法名称 | 说明 |
---|---|
void wait() | 让当前线程等待并释放所占锁,直到另一个线程调用notify()方法 或 notifyAll()方法 |
void notify() | 唤醒正在等待对象监视器(锁对象)的单个线程 |
void notifyAll() | 唤醒正在等待对象监视器(锁对象)的所有线程 |
注意:
- 上述方法应该使用当前同步锁对象进行调用。
package com.app.d7_thread_communication;
/**
账户类
*/
public class Account {
private double balance; // 账户余额
public Account() {
}
/**
亲爹、干爹、岳父:存钱10万元
*/
public synchronized void saveMoney(double money) {
try {
String name = Thread.currentThread().getName();
if (this.balance == 0) {
// 账户没钱:存钱
this.balance += money;
System.out.println(name + "来存钱了~~ 存钱后余额为:" + this.balance + "元");
// 存钱后:唤醒别人,等待自己
this.notifyAll(); // 唤醒所有线程
this.wait(); // 让当前线程进入等待~~
}else {
// 账户有钱:唤醒别人,等待自己
this.notifyAll(); // 唤醒所有线程
this.wait(); // 让当前线程进入等待~~
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
小明、小红:取钱10万元
*/
public synchronized void drawMoney(double money) {
try {
String name = Thread.currentThread().getName();
if (this.balance >= money) {
// 钱够,取钱
this.balance -= money; // 更新账户余额
System.out.println(name + "来取钱了~ 取钱后余额为:" + this.balance + "元");
// 取完钱,唤醒别人,等待自己
this.notifyAll(); // this:锁对象;唤醒所有线程
this.wait(); // 让当前线程进入等待~~
}else {
// 钱不够,唤醒别人,等待自己
this.notifyAll(); // this:锁对象;唤醒所有线程
this.wait(); // 让当前线程进入等待~~
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Account(double balance) {
this.balance = balance;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
package com.app.d7_thread_communication;
/**
存钱线程任务类
*/
public class SaveMoneyThread extends Thread {
// 接收处理的账户对象
private Account acc;
public SaveMoneyThread(Account acc, String name) {
super(name);
this.acc = acc;
}
/**
重写run方法(里面是三个爸爸的存钱线程任务)
*/
@Override
public void run() {
while (true) {
// 存钱10万元
acc.saveMoney(100000);
// 存完钱,让线程睡眠2秒钟
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package com.app.d7_thread_communication;
/**
取钱线程任务类
*/
public class DrawMoneyThread extends Thread {
// 接收处理的账户对象
private Account acc;
public DrawMoneyThread(Account acc, String name) {
super(name);
this.acc = acc;
}
/**
重写run方法(里面是小明、小红的取钱线程任务)
*/
@Override
public void run() {
while (true) {
// 取10万元
acc.drawMoney(100000);
// 取完钱让线程睡眠3秒钟
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package com.app.d7_thread_communication;
/**
目标:了解线程通信
需求:
小明和小红有三个爸爸:亲爹、干爹、岳父
必须一存一取:
三个爸爸负责存钱10万元
小明和小红负责取钱10万元
*/
public class ThreadDemo {
public static void main(String[] args) {
// 1、创建一个账户,代表5个人共同操作的账户
Account acc = new Account(0);
// 2、创建3个存钱线程代表三个爸爸:亲爹、干爹、岳父
new SaveMoneyThread(acc, "亲爹").start();
new SaveMoneyThread(acc, "干爹").start();
new SaveMoneyThread(acc, "岳父").start();
// 3、创建2个取钱线程代表小明和小红
new DrawMoneyThread(acc, "小明").start();
new DrawMoneyThread(acc, "小红").start();
}
}