为线程打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()方法,可能会出现下面的情况

 

猜你喜欢

转载自blog.csdn.net/weixin_42621338/article/details/82924411