什么是线程通信、如何实现?
所谓线程通信就是线程之间相互发送数据,线程通信通常通过共享一个数据的方式实现
线程之间会根据共享数据的情况决定自己改怎么做,以及通知其他线程怎么做
线程通信的常见模型
生产者与消费者模型:生产者线程负责生产数据,消费者线程负责消费数据
要求:生产者线程生产完数据后,唤醒消费者,然后等待自己,消费者消费完数据后,唤醒生产者,然后等待自己
线程通信常用三个方法
void wait() 当前线程等待,直到另一个线程调用notify()或者notiyall() 唤醒自己
void notify ( ) 唤醒正在等待对象监听器(锁对象) 的单个线程
void notifyAll() 唤醒正在等待对选哪个监听器(锁对象)的多个线程
注意:上述方法应当使用同步锁对象进行调用
案例模拟
一个家庭中,A和B在银行负责存钱,C,D,E在银行中负责取钱。(每次都是整存整取,有钱就不需要存,等待取钱后才可以继续存钱)
账户类(要公用一个账户)
package 线程通信案例;
/**
* 账户类
*/
public class Account {
private String cardID;
private double money;
/**
* @return the cardID
*/
public String getCardID() {
return cardID;
}
/**
* @param cardID the cardID to set
*/
public void setCardID(String cardID) {
this.cardID = cardID;
}
/**
* @return the money
*/
public double getMoney() {
return money;
}
/**
* @param money the money to set
*/
public void setMoney(double money) {
this.money = money;
}
public Account(String cardID, double money) {
super();
this.cardID = cardID;
this.money = money;
}
public Account() {
super();
}
/**
* 取钱方法多线程通信需要加锁
* @param money
*/
public synchronized void draw(Double money) {
// TODO Auto-generated method stub
String name=Thread.currentThread().getName(); //当前线程是谁就获取谁的线程名称
try {
if (this.money >= money) {
//有钱可以取钱
this.money -= money;
System.out.println(name + "来取钱" +money+"卡内还剩"+this.money);
this.notifyAll();
this.wait();
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 存钱方法
*/
public synchronized void deposit(double money) {
// TODO Auto-generated method stub
String name=Thread.currentThread().getName();
try {
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();
}
}
}
取钱线程
package 线程通信案例;
/**
* 取钱线程
* @author ASUS
*
*/
public class DrawMoneyThread extends Thread {
Account account;
//提供一个构造器
public DrawMoneyThread(Account account ,String name) {
super(name);
this.account=account;
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
account.draw(10000.0);//整存整取
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
存钱线程
package 线程通信案例;
/**
* 存钱线程
*/
public class DepositThread extends Thread{
Account account;
public DepositThread(Account account,String name) {
super(name);
this.account=account;
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
account.deposit(10000.0);
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
测试一下
package 线程通信案例;
public class Teat {
public static void main(String[] args) {
//创建卡号
Account ac=new Account("AA_001",0);
//线程通信要用同一对象
// 创建两个取钱线程
new DrawMoneyThread(ac,"取钱A").start();
new DrawMoneyThread(ac, "取钱B").start();
//创建3个存钱线程
new DepositThread(ac,"存钱C").start();
new DepositThread(ac, "存钱D").start();
new DepositThread(ac, "存钱E").start();
}
}
输出的一直都是(随机的)
存钱C来存钱10000.0卡内还剩10000.0
取钱B来取钱10000.0卡内还剩0.0
存钱E来存钱10000.0卡内还剩10000.0
取钱A来取钱10000.0卡内还剩0.0
存钱C来存钱10000.0卡内还剩10000.0
取钱B来取钱10000.0卡内还剩0.0
存钱C来存钱10000.0卡内还剩10000.0
取钱A来取钱10000.0卡内还剩0.0
存钱C来存钱10000.0卡内还剩10000.0
取钱B来取钱10000.0卡内还剩0.0
存钱D来存钱10000.0卡内还剩10000.0
取钱A来取钱10000.0卡内还剩0.0
存钱C来存钱10000.0卡内还剩10000.0
取钱B来取钱10000.0卡内还剩0.0
存钱D来存钱10000.0卡内还剩10000.0
取钱A来取钱10000.0卡内还剩0.0
存钱C来存钱10000.0卡内还剩10000.0
取钱B来取钱10000.0卡内还剩0.0