目标:线程通信
线程通信:
多个线程因为在同一个进程中,所以互相通信比较容易的。
线程通信的经典模型:
生产者与消费者问题。
生产者负责生成商品,消费者负责消费商品。
生产不能过剩,消费不能没有。
厂家 口红 消费者。
模拟一个案例:
小明和小红有一个共同账户:共享资源
他们有3个爸爸(亲爸,岳父,干爹)给他们存钱。
模型:小明和小红去取钱,如果有钱就取出,然后等待自己,唤醒他们3个爸爸们来存钱
他们的爸爸们来存钱,如果发现有钱就不存,没钱就存钱,然后等待自己,唤醒孩子们来取钱。
做整存整取:10000元。
分析:
生产者线程:亲爸,岳父,干爹
消费者线程:小明,小红
共享资源:账户对象。
注意:线程通信一定是多个线程在操作同一个资源才需要进行通信。
线程通信必须先保证线程安全,否则毫无意义,代码也会报错!
线程通信的核心方法:
public void wait(): 让当前线程进入到等待状态 此方法必须锁对象调用.
public void notify() : 唤醒当前锁对象上等待状态的某个线程 此方法必须锁对象调用
public void notifyAll() : 唤醒当前锁对象上等待状态的全部线程 此方法必须锁对象调用
public class ThreadCommunication {
public static void main(String[] args) {
// 1.创建1个账户对象。
Account acc = new Account(0 , "ICBC-111");
// 2.创建消费者线程:小明/小红 取钱
new DrawThread(acc,"小明").start();
new DrawThread(acc,"小红").start();
// 3.创建生产者线程:亲爸,岳父,干爹
new SaveThread(acc,"亲爸").start();
new SaveThread(acc,"岳父").start();
new SaveThread(acc,"干爹").start();
}
}
账户类
public class Account {
private double money ; // 余额
private String cardId ;
// 创建一把锁对象
private final Lock lock = new ReentrantLock();
public Account(){
}
public Account(double money, String cardId) {
this.money = money;
this.cardId = cardId;
}
// 亲爸,干爹,岳父
public synchronized void saveMoney(double money) {
try{
String name = Thread.currentThread().getName();
if(this.money > 0){
// 有钱,不需要存钱
this.notifyAll(); // 唤醒别人
this.wait();// 等待自己,释放锁!
}else{
// 没钱
this.money += money;
System.out.println(name+"来存钱,存钱后剩余:"+this.money);
this.notifyAll(); // 唤醒别人
this.wait();// 等待自己,释放锁!
}
}catch (Exception e){
e.printStackTrace();
}
}
// 小明,小红
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{
// 余额不足。
this.notifyAll(); // 唤醒别人
this.wait();// 等待自己,释放锁!
}
}catch (Exception e){
e.printStackTrace();
}
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
}
存钱的线程类。
public class SaveThread extends Thread {
private Account acc ;
public SaveThread(Account acc , String name){
super(name);
this.acc = acc;
}
@Override
public void run() {
// 亲爸,干爹,岳父
while(true){
acc.saveMoney(10000);
}
}
}
取钱的线程类
public class DrawThread extends Thread {
private Account acc ;
public DrawThread(Account acc , String name){
super(name);
this.acc = acc;
}
@Override
public void run() {
while(true){
// 小明 小红
acc.drawMoney(10000);
}
}
}