为线程打Call——通信之消费者生产者模型
为什么要线程通信
- 多线程并发时,默认情况下CPU是随机切换线程的。当我们需要多个线程共同来完成一个任务,并且希望他们有规律的执行,那么线程之间就需要有一些协调的通信,以此来达到多个线程来操作一份数据。
- 当然了,如果没有这种协调通信也是可以完成多线程操作同一份数据的,但是很有可能会出现线程对同一变量的争夺,这种情况就会出错。所以简而言之,线程通信就是为了避免多线程对同一共享变量的争夺。
这是没有设置通信的多线程操作同一数据的结果
public class Manager {
public static void main(String[] args) throws InterruptedException {
Account ac = new Account(4000);
GetCash gcATM = new GetCash(ac, "ATM取款", 2500);
GetCash gcBANK = new GetCash(ac,"柜台取款", 2500);
gcATM.start();
gcBANK.start();
Thread.sleep(5000);
System.out.println(ac);
}
}
public class GetCash extends Thread{
private Account ac;
private String flag;//取款方式
private int disCount;//金额
public GetCash(Account ac, String flag, int disCount) {
super();
this.ac = ac;
this.flag = flag;
this.disCount = disCount;
}
@Override
public void run() {
//取钱
int cash = ac.getCash(disCount);
System.out.println(flag+"取了:"+cash);
}
}
public class Account {
private int total;
//构造存有指定金额的银行账户
public Account(int save) {
this.total = save;
}
//从账户上提取现金的调用方法
public int getCash(int count) {
//金额不足
if(total<count) {
return -1;
}
disSave(count);
return count;
}
//从账户减去提取金额的过程
private void disSave(int count) {
total = total-count;
}
public String toString() {
return "账户余额:"+total;
}
}
解决办法:
使用同步锁synchronized锁住要对变量进行操作的方法或者代码块,比如此处的getCash()、disSave()方法 。这样就不会产生线程的争夺了。
到底什么是线程通信呢?
- 多个线程在处理同一个资源 ,并且任务不同时,需要线程通信来帮助进行同一变量的使用和操作,避免多个线程在操作同一变量时争夺。
如何实现线程通信?
- synchronized锁
上面的代码已经提到不再举例
- wait / notify 机制(消费者、生产者模型)
实际上消费者、生产者模型也只是利用了wait()、notify()方法来控制对象锁的拥有权,并没有什么多余的知识······
public class Bank {
private int product = 0;
private int max_product = 10;
private int min_product = 1;
public synchronized void add() {
if(product>=max_product) {
try {
wait();
System.out.println("产品仓库放满了,停止生产中···");
} catch (InterruptedException e) {
e.printStackTrace();
}
return;
}
product ++;
System.out.println("生产了第"+product+"个产品");
notifyAll();
}
public synchronized void remove() {
if(product<min_product) {
try {
wait();
System.out.println("产品仓库空了,缺货中···");
} catch (InterruptedException e) {
e.printStackTrace();
}
return;
}
System.out.println("消费了第"+product+"个产品");
product --;
notifyAll();
}
}
public class Producer extends Thread{
private Bank bank;
public Producer(Bank bank) {
super();
this.bank = bank;
}
@Override
public void run() {
System.out.println("开始生产产品···");
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bank.add();
}
}
}
public class Consumer extends Thread{
private Bank bank;
public Consumer(Bank bank) {
super();
this.bank = bank;
}
@Override
public void run() {
System.out.println("开始消费产品");
while(true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
bank.remove();
}
}
}
public class Manager {
public static void main(String[] args) {
Bank bank = new Bank();
Producer pd = new Producer(bank);
Consumer cs = new Consumer(bank);
pd.start();
cs.start();
}
}
至于消费产品和生产产品的优先顺序,就看线程自己抢占资源的能力了。但是由于存在wait / notify机制,并不会出现数据错误不符合事实的情况出现。
若不使用wait()、notify()方法,可能会出现下面的情况