这一篇说一下生产者与消费者问题,这是操作系统里有比较经典的问题。在操作系统里生产者与消费者问题是解决进程同步问题提出来的一种方法,但在线程里同样适用。我们先来想一下,为什么要提出生产者与消费者问题?
和操作系统一样,JAVA多线程的生产者与消费者问题一样是为解决同步而产生的,可是解决同步上一篇里面用synchronized,做一个标志位已经做到了。还要生产者和消费者问题干什么。synchronized来做到的线程同步解决不了实际上的需求,例如一家物流公司进行运货,他不可能来一件货物,他就马上叫司机把这件货物运到指定的地方。而是将一批批货物,积压到一定的需求,进行分类,然后叫司机去运这些货物。
生产者与消费者问题,就是差不多有这么一个仓库,生产者生产货物放到这么一个仓库,仓库积压到一定的程度后再进行消费。这个是用synchronized来做一个标志位没法做到的。
我们先来看一段程序,关于不同步的生产者与消费者带来的问题
class Q
{
String name = "none";
String sex = "none";
}
class Producer implements Runnable
{
Q q;
Producer(Q q)
{
this.q = q;
}
public void run()
{
int i=0;
while(true)
{
if(i==0)
{
q.name = "张三";
try{ Thread.sleep(1);}
catch(Exception e){}
q.sex = "男";
}
else
{
q.name = "李静";
q.sex = "女";
}
i=(i+1)%2;
}
}
}
class Consumer implements Runnable
{
Q q;
Consumer(Q q)
{
this.q = q;
}
public void run()
{
while(true)
{
System.out.println(q.name+":"+q.sex);
}
}
}
public class test11
{
public static void main(String[] args)
{
Q q = new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}
}
我们运行后发现,本来应该输出的结果都是 张三 男,结果他输出了一些结果是 张三 女
用synchronized来解决生产者与消费者问题
class Q
{
String name = "none";
String sex = "none";
}
class Producer implements Runnable
{
Q q;
Producer(Q q)
{
this.q = q;
}
public void run()
{
int i=0;
while(true)
{
synchronized(q)
{
if(i==0)
{
q.name = "张三";
try{ Thread.sleep(1);}
catch(Exception e){}
q.sex = "男";
}
else
{
q.name = "李静";
q.sex = "女";
}
i=(i+1)%2;
}
}
}
}
class Consumer implements Runnable
{
Q q;
Consumer(Q q)
{
this.q = q;
}
public void run()
{
while(true)
{
synchronized(q)
{
System.out.println(q.name+":"+q.sex);
}
}
}
}
public class test11
{
public static void main(String[] args)
{
Q q = new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}
}
真正解决生产者与消费者问题的写法
class Q
{
String name = "none";
String sex = "none";
boolean bFull = false;
}
class Producer implements Runnable
{
Q q;
Producer(Q q)
{
this.q = q;
}
public void run()
{
int i=0;
while(true)
{
synchronized(q)
{
if(q.bFull)
try{ q.wait(); } catch( Exception e){}
if(i==0)
{
q.name = "张三";
try{ Thread.sleep(1);}
catch(Exception e){}
q.sex = "男";
}
else
{
q.name = "李静";
q.sex = "女";
}
i=(i+1)%2;
//装完后
q.bFull = true;
q.notify();
}
}
}
}
class Consumer implements Runnable
{
Q q;
Consumer(Q q)
{
this.q = q;
}
public void run()
{
while(true)
{
synchronized(q)
{
if(!q.bFull)
try{ q.wait(); } catch( Exception e){}
System.out.println(q.name+":"+q.sex);
//输出出来
q.bFull = false;
q.notify();
}
}
}
}
public class test11
{
public static void main(String[] args)
{
Q q = new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}
}
这里使用了wait和notify两个方法。他的思路过程是这样的:在生产者里判断bFull是否为true,如果他是true说明消费者正在消费,那么生产者等待,否则他开始生产,生产到一定程度后,他将bFull设为true并使用notify方法通知消费者他生产完了,消费者收到通知后,也判断bFull是否为true,如果是那么他开始消费,消费完毕后他通知生产者,他消费完了,你又可以再开始生产了。
使用面向对象的方式来进一步写生产者与消费者问题
class Q { private String name = "none"; private String sex = "none"; private boolean bFull = false; public synchronized void put(String name,String sex) { if(bFull) try{ wait(); } catch( Exception e){} this.name = name; try{ Thread.sleep(1); } catch( Exception e){} this.sex = sex; bFull = true; notify(); } public synchronized void get() { if(!bFull) try{ wait(); } catch( Exception e){} System.out.println(name+":"+sex); bFull = false; notify(); } } class Producer implements Runnable { Q q = null; public Producer(Q q) { this.q = q; } public void run() { int i=0; while(true) { if(i==0) { q.put("张三","男"); } else { q.put("李四","女"); } i=(i+1)%2; } } } class Consumer implements Runnable { Q q; public Consumer(Q q) { this.q = q; } public void run() { while(true) { q.get(); } } } public class test11 { public static void main(String[] args) { Q q = new Q(); new Thread(new Producer(q)).start(); new Thread(new Consumer(q)).start(); } }