java—生产者与消费者相关问题研究

一:单生产者单消费者:

分析:

  1. 两个线程:生产线程,消费线程
  2. 两个任务:生产任务,消费任务
  3. 一份数据

 

public class Demo03 {
	public static void main(String[] args) {
		//1.准备数据
		Product product = new Product();
		//2.创建生产消费任务
		Producer producer = new Producer(product);
		Consumer consumer = new Consumer(product);
		//3.创建生产消费线程
		Thread thread1 = new Thread(producer);
		Thread thread2 = new Thread(consumer);
		//4.开启线程
		thread1.start();
		thread2.start();
	}
}

// 数据类
class Product {
	String name;
	double price;
	int count;

	// 标识
	boolean flag ;// 默认是false

	// 准备生产
	public synchronized void setProduct(String name, double price) {
		if (flag == true) {
			try {
				wait();
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
		this.name = name;
		this.price = price;

		System.out.println(Thread.currentThread().getName() + "生产了:" + name + "  产品的数量:" + count + "  价格是:" + price);

		count++;

		flag = !flag;

		notify();
	}

	// 准备消费
	public synchronized void consume()  {
		if (flag == false) {
			try {
				wait();
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName() + "消费了:" + name + "  产品的数量:" + count + "  价格是:" + price);
		flag = !flag;
		notify();
	}
}

// 生产任务
class Producer implements Runnable {
	Product product;

	public Producer(Product product) {
		super();
		this.product = product;
	}

	public void run() {
		int i = 0;
		while (true) {

			product.setProduct("肯德基", 100);

		}
	}
}

// 消费任务
class Consumer implements Runnable {
	Product product;

	public Consumer(Product product) {
		super();
		this.product = product;
	}

	public void run() {
		while (true) {
			product.consume();
		}
	}
}

 

二:多生产者多消费者:

分析

  1. 两个线程:生产线程,消费线程
  2. 两个任务:生产任务,消费任务
  3. 一份数据

 

 错误描述:当有两个生产线程,两个消费线程同时存在的时候,有可能出现生产一次,消费多次或者生产多次消费一次的情况.

 原因:当线程被重新唤醒之后,没有判断标记,直接执行了下面的代码
 
 解决办法:将标记处的if改成while
 
 问题描述:继续运行程序,会出现死锁的情况(4个线程同时处于等待状态)
 原因:唤醒的是本方的线程,最后导致所有的线程都处于等待状态.
 
 解决办法:将notify改成notifyAll.保证将对方的线程唤醒
 
 死锁:出现的情况有两种
 1.所有的线程处于等待状态
 2.锁之间进行嵌套调用

 

public class Demo04 {
	public static void main(String[] args) {
		//1.准备数据
		Product1 product = new Product1();
		//2.创建生产消费任务
		Producer1 producer = new Producer1(product);
		Consumer1 consumer = new Consumer1(product);
		//3.创建生产消费线程
		Thread thread1 = new Thread(producer);
		Thread thread2 = new Thread(consumer);
		Thread thread3 = new Thread(producer);
		Thread thread4 = new Thread(consumer);
		//4.开启线程
		
		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();
	}
}

// 数据类
class Product1 {
	String name;
	double price;
	int count;

	// 标识
	boolean flag ;// 默认是false
 
	// 准备生产
	public synchronized void setProduct(String name, double price) {
		while (flag == true) {
			try {
				wait();
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
		this.name = name;
		this.price = price;

		System.out.println(Thread.currentThread().getName() + "生产了:" + name + "  产品的数量:" + count + "  价格是:" + price);

		count++;

		flag = !flag;

		notifyAll();
	}

	// 准备消费
	public synchronized void consume()  {
		while (flag == false) {
			try {
				wait();
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName() + "消费了:" + name + "  产品的数量:" + count + "  价格是:" + price);
		flag = !flag;
		notifyAll();
	}
}

// 生产任务
class Producer1 implements Runnable {
	Product1 product;

	public Producer1(Product1 product) {
		super();
		this.product = product;
	}

	public void run() {
		int i = 0;
		while (true) {

			product.setProduct("肯德基", 100);

		}
	}
}

// 消费任务
class Consumer1 implements Runnable {
	Product1 product;

	public Consumer1(Product1 product) {
		super();
		this.product = product;
	}

	public void run() {
		while (true) {
			product.consume();
		}
	}
}


 研究:研究Lock
  比较synchronized和Lock


  1.synchronized:从jdk1.0就开始使用的同步方法-称为隐式同步
      synchronized(锁对象){//获取锁      我们将锁还可以称为锁旗舰或者监听器
          同步的代码
  }//释放锁


  2.Lock:从jdk1.5开始使用的同步方法-称为显示同步
  
  原理:Lock本身是接口,要通过他的子类创建对象干活儿
  使用过程:
  首先调用lock()方法获取锁
     进行同步的代码块儿
     使用unlock()方法释放锁
   
  使用的场景:
  当进行多生产者多消费者的功能时,使用Lock,其他的都使用synchronized
   
  使用效率上:Lock高于synchronized

public class Demo05 {
	public static void main(String[] args) {
		// 1.准备数据
		Product2 product = new Product2();
		// 2.创建生产消费任务
		Producer2 producer = new Producer2(product);
		Consumer2 consumer = new Consumer2(product);
		// 3.创建生产消费线程
		Thread thread1 = new Thread(producer);
		Thread thread2 = new Thread(consumer);
		Thread thread3 = new Thread(producer);
		Thread thread4 = new Thread(consumer);
		// 4.开启线程

		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();

	}
}

// 数据类
class Product2 {
	String name;
	double price;
	int count;

	// 标识
	boolean flag;// 默认是false

	// 创建锁对象
	Lock lock = new ReentrantLock();
	
	//获取为生产任务提供唤醒等待的Condition对象
	Condition conditionPro = lock.newCondition();
	//获取为消费任务提供唤醒等待的Condition对象
	Condition conditionCon = lock.newCondition();

	
	// 准备生产
	public void setProduct(String name, double price) {
		try {
			lock.lock();// 获取锁

			while (flag == true) {
				try {
					conditionPro.await();//让生产线程等待
				} catch (Exception e) {
					// TODO: handle exception
					e.printStackTrace();
				}
			}
			this.name = name;
			this.price = price;

			System.out
					.println(Thread.currentThread().getName() + "生产了:" + name + "  产品的数量:" + count + "  价格是:" + price);

			count++;

			flag = !flag;
			
			//肯定唤醒的是消费线程
			conditionCon.signal();
			
		} finally {//放的是必须执行的代码,功能:用于资源的释放
			lock.unlock();// 释放
		}
	}

	// 准备消费
	public void consume() {
		try {
			lock.lock();
			while (flag == false) {
				try {
					conditionCon.await();//让消费进程等待
				} catch (Exception e) {
					// TODO: handle exception
					e.printStackTrace();
				}
			}
			System.out.println(Thread.currentThread().getName() + "消费了:" + name + "  产品的数量:" + count + "  价格是:" + price);
			flag = !flag;
			
			//肯定唤醒的是生产线程
			conditionPro.signal();
			
		} finally {
			// TODO: handle finally clause
			lock.unlock();
		}
		
	}
}

// 生产任务
class Producer2 implements Runnable {
	Product2 product;

	public Producer2(Product2 product) {
		super();
		this.product = product;
	}

	public void run() {
		int i = 0;
		while (true) {

			product.setProduct("肯德基", 100);

		}
	}
}

// 消费任务
class Consumer2 implements Runnable {
	Product2 product;

	public Consumer2(Product2 product) {
		super();
		this.product = product;
	}

	public void run() {
		while (true) {
			product.consume();
		}
	}
}

线程的停止:即如何停止它的任务

  1. 通过一个标识结束线程
  2. 调用stop方法——有固有的安全性问题,系统不推荐使用。
  3. 调用interrupt()方法。

 

//第一种方式:
/*public class Demo06 {
	public static void main(String[] args) {
		Test test = new Test();
		Thread thread = new Thread(test);
		thread.start();
		
		try {
			thread.sleep(100);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
		
		int i = 0;
		while(true) {
			if(++i==10) {
				test.flag=false;//当主线程执行到某个阶段时,让flag变成false,子线程的任务就会结束,子线程就结束了。
				
				break; //目的是让主线程结束
			}
		}
		
	}
}

class Test implements Runnable {
	boolean flag = true;
	
	public void run() {
		while(flag) {
			System.out.println(Thread.currentThread().getName()+"该下课了");
			
		}
	}
}*/

//第三种方式
public class Demo06 {
	public static void main(String[] args) {
		Test test = new Test();
		Thread thread = new Thread(test);
		thread.start();
		
		try {
			thread.sleep(100);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
		
		int i = 0;
		while(true) {
			if(++i==10) {
				
				//当主线程执行到某个阶段是,调用子线程的Interrupt方法,触发子线程的异常(InterruptedException),让子线程的任务结束,子线程结束
				thread.interrupt();
				break; //目的是让主线程结束
			}
		}
		
	}
}

class Test implements Runnable {
	boolean flag = true;
	
	public synchronized void run() {
		while(flag) {
			try {
				wait();
			} catch (InterruptedException e) {
				flag=false;
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"该下课了");
			
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值