Exception in thread "Thread-0" java.lang.IllegalMonitorStateException

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException

线程“thread -0”java.lang.IllegalMonitorStateException中的异常

 


/**
 * 
 * Title:生产者
 * Description:
 * @author lcs
 * @date 2018年12月12日
 * @version 1.0
 */
public class Productor implements Runnable{
	private static String[] goodsType={"iPhone7", "iPhone8", "iPhoneX", "博世冰箱", "格力空调", "吉利房车", 
			"电动汽车", "思科路由器", "华为交换机", "大疆无人机"};
	private static final int STORE_MAX = 1000;
	//单例,getProductor
	private static Productor productor=null;
	public static Productor getProductor(){
		if(productor == null)
			productor =new Productor();
			//创建的时候就使用无参构造方法
			
		return productor;
		
	}
	//编写无参构造方法
	private Productor(){
		//要给出具体的实现方法,总是增删改,所以用linkedList方法
		store = new LinkedList<Goods>();
	}
	//库存
	private List<Goods> store;
	
	//再搞把锁对象
	private Object lock;
	
	public void setLock(Object lock)
	{
		this.lock=lock;
	}
	
	//此方法为从库存中获取一个商品的最基本操作
	//此方法只会在消费者线程中调用,因此我们可以在消费者处进行同步
    //库存store也是private的,消费这个操作不好直接对库存进行操作 
    //是给Consumer配置的方法,增加是add往最后加,那么消费的时候就remove(0),从头拿
    //有一个就拿一个,疑问若有类型A的东西,但没有类型b的东西,但是拿b怎么办?
	public Goods getOneGoods()
	{
		Goods g =null;
		if (store.size()==0) 
			return null;
		
		g=store.remove(0);
		//打印库存剩余产品数量
		System.out.println("消费一个商品,库存目前剩余:" + store.size());
		return g;
	}
	
	
	//一次生产N个产品,N设定为5-10
	//一批产品,为能够生产的10种中的同一种产品
	private void produceGoods(){
		//随机出本次商品的数量
		int n= (int) (Math.random()*101+50);
		//随机出商品的种类
		int type= (int) (Math.random()*10);
		String gType=goodsType[type];
		int i;
		synchronized (lock) {
			for ( i = 0; i < n; i++) {
				if (store.size()==STORE_MAX) {
					break;
				}
				Goods g=Goods.createOneGoods(gType);
				store.add(g);
			}
			System.out.println("生产商本次一共生产了:" + i + "个" + gType + "商品。库存目前为:" + store.size());
		}
		if(store.size()==STORE_MAX){
			System.out.println("*****************库存已满!!!生产者进入等待模式!!!*****************");
			try {
				lock.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		//缺少少于多少个的唤醒!!!!!!!!!!!!!生产者!!!!!!
		
		}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true)
		{
			//什么东西往这里写????
			
			//当然是有冲突的东西写进来啊!!!!!和synchinize块里面有什么区别???????
			
			//生产东西的时候你要消费的话,数目上就冲突了啊
			//所以生产商品的这个方法在里面
			produceGoods();
			try {
//意思是不可能让一直生产,cpu主频很快,得休息一下啊
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}

出现这个问题是没有把判断条件放入到synchronized方法块里面

生产者和消费者两个都是多线程,不管别人怎么样,自己生产,同时也消费

synchronized(this) //锁住当前对象的引用,则任何线程通过当前线程访问到此句,会锁住,直到放开锁,其他线程才能进来。

重写run方法:run()称为线程体,它包含了要执行的这个线程的内容Run方法运行结束,此线程终止,而CPU再运行其它线程

想想哪里可能有线程冲突:1,生产的时候add,另一个线程消费了remove了,底层不知道,尼玛你到底想干嘛,我操2,一个线程看到还有一个产品,两个线程同时去消费这个产品,产生空指针异常

所以呢,方法前面加synchronized,但是Productor是一个单例对象,这个对象拿来同步,但是Consumer怎么同步呢?

所以,把对生产者库存的这个数据要保护起来,把跟集合有关系的包进来

package com.chinasofti.ProductorConsumer;

public class Goods {
	//当前一共产出了多少个货物
	public static int count = 0;
	
	//生产了产品,name就是
	public static Goods createOneGoods(String name)
	{
		count++;
		return new Goods(count,name);
	}
	
	private Goods(int id, String name) {
		this.id = id;
		this.name = name;
	}
	
	
	private int id;//一个货物对象一个id编号
	private String name;
	@Override
	public String toString() {
		return "Goods [id=" + id + ", name=" + name + "]";
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}

 

package com.chinasofti.ProductorConsumer;

public class Consumer extends Thread{
	private static int consumedGoods = 0;
	private Object lock;
	
	public Consumer(String name){
		super(name);
	}


	public void setLock(Object lock) {
		this.lock = lock;
	}
	
	private void consumeGoods(){
		//一次消费N个商品,从生产商处拿货
		int n = (int)(Math.random()*2 + 1);//一次消费10-20个商品
		synchronized (lock) {
			for(int i=0;i<n;i++){
				Goods g = Productor.getProductor().getOneGoods();
				if (g==null) {
					System.out.println("顾客:" + Thread.currentThread().getName() + "本次消费完毕,库存已空!");
					lock.notify();//库存已空,消费者通知生产者恢复生产
					break;
				}
				consumedGoods++;
				
				System.out.println("顾客:" + Thread.currentThread().getName() + "本次消费了商品:" + g.getName() + ",商品的编号为:" + g.getId()
				+ "。所有消费者目前一共消费了:" + consumedGoods + "个商品!");
			}
		}
	}


	@Override
	public void run(){
		while (true) {
			consumeGoods();
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
package com.chinasofti.ProductorConsumer;

public class TestClass {
	public static void main(String[] args) {
		Object lock =new Object();
		//生产者消费者都用一个锁
		Thread productor =new Thread(Productor.getProductor());
		Productor.getProductor().setLock(lock);
		productor.start();
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//十个顾客
		for(int i=0;i<10;i++)
		{
			Consumer consumer =new Consumer("顾客"+i+1);
			consumer.setLock(lock);
			consumer.start();
		}
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值