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();
}
}
}