Java中多线程的生产者和消费者的演示
1.多线程的操作
多线程中的生产者消费者至少操作了两个线程,如果是多生产多消费的模式则涉及到大于两个的多线程模式。
设计生产者与消费者线程,实现多生产多消费的模式。
package tread;
public class ThreadTest {
public static void main(String[] args) {
Res res=new Res();
Producer pro=new Producer(res);
Consumer con=new Consumer(res);
Thread t1=new Thread(pro);
Thread t2=new Thread(pro);
Thread t3=new Thread(con);
Thread t4=new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//生产者
class Producer implements Runnable {
private Res res;
Producer(Res res) {
this.res=res;
}
@Override
public void run() {
while(true) {
res.set("面包");
}
}
}
//消费者
class Consumer implements Runnable{
private Res res;
Consumer(Res res) {
this.res=res;
}
@Override
public void run() {
while(true) {
res.get();
}
}
}
//资源
class Res{
private String name;
private int count=1;
private boolean flag=false;
public synchronized void set(String name) {
while(flag)
try {
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
this.name=name+"--"+count;
System.out.println(Thread.currentThread().getName()+"---生产者---"+this.name);
count++;
flag=true;
notifyAll();
}
public synchronized void get() {
while(!flag)
try {
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"---消费者---"+this.name);
flag=false;
notifyAll();
}
}
2.分析:生产者和消费者线程都有共享的资源Res,为了资源操作是同一个资源,采用创建Producer和Consumer时同时创建资源。资源中的set()与get()方法加了同步机制,避免了cpu切换线程时造成方法没执行完就执行另一个方法的问题。资源中添加了flag标记,用来判断资源是否消费完,flag初值为false,如果flag为false,则生产者生产,生产完将flag更改为true,当flag为true时,消费者开始消费,消费完成后将flag更改为false,这样就形成了一个生产和消费的循环。但是还有一个问题,我们的生产和消费线程是由cpu来自由切换的,这就会产生多次生产、多次消费的问题。所有我们要通过线程的通讯方式来约束线程的开启和冻结。首先,我们判断flag,如果flag为true时,生产者停止生产,线程冻结(wait()),如果flag为false时,生产者开始生产,生产完成后唤醒所有线程(notify All()),但是当生产者线程被唤醒并进入cpu执行时,我们设计的是一个while循环判断,这时的flag为true,所有就算开启了生产者线程,当它执行时就进入了wait()。这时唤醒并执行了消费者线程,第一步还是判断flag,如果为false,则线程进入wait(),如果为true,则进行消费行为,完成线程目标之后又唤醒所有线程(notify All()),同样还是循环判断防止消费者的多次消费问题。
运行
2.JDK1.5以上的Lock对象的使用
因为使用同步函数时,锁与监视器是所有对象,不能进行嵌套使用(死锁),所有每次唤醒线程需要唤醒所有线程,不合理。
解决方法:使用1.5版本以上的JDK,其中有一个Lock对象,可以代替同步函数,Lock可以同时拥有多个监视器Condition。
package thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadLockTest {
public static void main(String[] args) {
Res res=new Res();
Producer pro=new Producer(res);
Consumer con=new Consumer(res);
Thread t1=new Thread(pro);
Thread t2=new Thread(pro);
Thread t3=new Thread(con);
Thread t4=new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Producer implements Runnable {
private Res res;
Producer(Res res) {
this.res=res;
}
@Override
public void run() {
while(true) {
res.set("面包");
}
}
}
class Consumer implements Runnable{
private Res res;
Consumer(Res res) {
this.res=res;
}
@Override
public void run() {
while(true) {
res.get();
}
}
}
class Res{
private String name;
private Lock lock=new ReentrantLock();
//生产者监视器
private Condition producer_con=lock.newCondition();
//消费者监视器
private Condition consumer_con=lock.newCondition();
private int count=1;
private boolean flag=false;
public void set(String name) {
lock.lock();
try {
while(flag)
try {
producer_con.await();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
this.name=name+"--"+count;
System.out.println(Thread.currentThread().getName()+"---生产者---"+this.name);
count++;
flag=true;
consumer_con.signal();}
finally {lock.unlock();}
}
public void get() {
lock.lock();
try {
while(!flag)
try {
consumer_con.await();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"---消费者---"+this.name);
flag=false;
producer_con.signalAll();}
finally {lock.unlock();}
}
}
运行