浅谈多线程生产者与消费者
在我们进行项目开发时我们需要程序同时运行不同的功能代码,也就是所说的不同任务,这时我们会考虑使用线程进行实现。最经典的例子莫属生产者与消费者模式线程开发。
本人简单实现代码如下:
package com.cai;
public class productDemo {
public static void main(String[] args) {
Resource r = new Resource();
productor p1 = new productor(r);
Consumer c1= new Consumer(r);
Thread t1 = new Thread(p1);
Thread t2 = new Thread(p1);
Thread t3 = new Thread(c1);
Thread t4 = new Thread(c1);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Resource{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void setName(String name){
while(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
flag = true;
notifyAll();
}
public synchronized void output(){
while(!flag){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.err.println(Thread.currentThread().getName()+"...消费者........"+this.name);
flag = false;
notifyAll();
}
}
public static void main(String[] args) {
Resource r = new Resource();
productor p1 = new productor(r);
Consumer c1= new Consumer(r);
Thread t1 = new Thread(p1);
Thread t2 = new Thread(p1);
Thread t3 = new Thread(c1);
Thread t4 = new Thread(c1);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Resource{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void setName(String name){
while(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
flag = true;
notifyAll();
}
public synchronized void output(){
while(!flag){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.err.println(Thread.currentThread().getName()+"...消费者........"+this.name);
flag = false;
notifyAll();
}
}
class productor implements Runnable{
private Resource r;
public productor(Resource r){
this.r=r;
}
public void run() {
while(true){
r.setName("java");
}
}
}
class Consumer implements Runnable{
private Resource r;
Consumer(Resource r){
this.r=r;
}
public void run() {
while(true){
r.output();
}
}
}
执行效果如下:
简单解析:
这里我们要注意一些问题在我们判断线程标志时我们使用while是为了防止生产者生产了几个而消费者未进行消费,原因是如果我们生产者线程1,线程2分别等待,消费者进行唤醒后,生产者线程1获取锁执行后生产了一个,此时标志改为true,那么生产者线程2此时获取了cpu执行权,接着向下执行又生产了一个,生产者线程1此时获取cpu执行权得到标志进行等待,消费者线程1获取执行权判断条件false向下进行执行消费,标志为false此时可能唤醒生产者消费2,标志位false,向下生产,又产生了一个一次分析可知,生产者生产几个而消费者只消费了1个显然不满足生产一个消费一个的需求。在此时我们使用while来进行标志判断,等待之后进行标志获取,此时以上面的进行推理可能形成一个线程死锁,那么此时我们就应该在生产或消费之后来唤醒所有的线程,这样我们的需求才得以满足。
if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。
while判断标记,解决了线程获取执行权后,是否要运行!
while判断标记,解决了线程获取执行权后,是否要运行!
notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。
notifyAll解决了本方线程一定会唤醒对方线程的问题。
notifyAll解决了本方线程一定会唤醒对方线程的问题。