1. 分析:(生产者-消费者问题是多线程同步处理的典型问题)
有一块生产者和消费者共享的有界缓冲区,生产者往缓冲区放入产品,消费者从缓冲区取走产品,这个过程可以无休止的执行,不能因缓冲区满生产者放不进产品而终止,也不能因缓冲区空消费者无产品可取而终止。
2. 解决生产者消费者问题的方法
一种是采用某种机制保持生产者和消费者之间的同步
一种是在生产者和消费者之间建立一个管道
线程的同步解决生产者-消费者问题
限制公共缓冲区不能被两个线程同时访问,需要使用互斥锁,即用synchronized来标识同步资源。但加了互斥锁以后有可能会造出死锁。这时需要wait()方法和notify()方法--当前线程被阻塞并释放该对象的互斥锁。
3. 通过上面的分析,大致了解了一下思路,下面用代码案例解说一下:
packagecom.javaEE.code.put;
//资源类
class Res{
String name;
String sex;
boolean b; //设置一个旗帜,用来判断运用wait()方法时是否释放资源,在这里声明的boolean型java系统默认为false。
}
//模拟生产者,生成产品
class Inputimplements Runnable{
private Res r;
public Input(Res r) {
this.r = r;
}
public void run() {
int x = 0;
while(true){
//运用线程同步来避免生成者还没生产消费者就来输出、生产者生产好多了消费者才来、输出产品混乱(比如此例中的姓名张三性别gril的劣质产品问题)问题隐患
synchronized(r){
if(r.b){ //这里为假暂不执行
try {
r.wait();
} catch(InterruptedException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
}
if(x==0){
r.name = "张三";
r.sex = "男";
}else{
r.name ="jane";
r.sex = "girl";
}
r.b = true; //将旗帜设置为假
r.notify(); //发出通讯,通知消费者
}
x = (x+1)%2;
}
}
}
//模拟消费者,输出产品
class Outputimplements Runnable{
private Res r;
public Output(Res r) {
this.r = r;
}
public void run() {
while(true){
synchronized(r){
if(!r.b){
try {
r.wait();
} catch(InterruptedException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
}
System.out.println("生产产品名称:"+r.name+"......"+"生成产品类别:"+r.sex);
r.b = false;
r.notify();
}
}
}
}
public classThreadPut {
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
4.以上代码还可以优化,优化后的代码为:
这里用的是同步线程的synchronized函数,而上面例子中用的是代码块。这里把同步线程的代码都放到了资源类中。
packagecom.javaEE.code.put;
class Res1{
String name;
String sex;
boolean flag;
public synchronized void set(Stringname,String sex){
if(flag)
try {
wait();
} catch (InterruptedExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
this.name = name;
this.sex = sex;
flag = true;
notify();
}
}
public synchronized void out(){
if(!flag)
try {
wait();
} catch (InterruptedExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
System.out.println("生产产品名称:"+name+"......"+"生成产品类别:"+sex);
flag = false;
notify();
}
}
class Input1implements Runnable{
private Res1 r;
public Input1(Res1 r) {
this.r = r;
}
public void run() {
int x = 0;
while(true){
/*这里不像前面的例子,用个限制次数的for循环来终止循环,这里如果用for循环迭代语句i++并没有执行
就进入synchronized代码库中了,然后生产然后通知输出,通知完之后再次生产回到这里又重新开新了!*/
if(x==0){
r.set("张三", "男");
}else{
r.set("jane","girl");
}
x = (x+1)%2;
}
}
}
class Output1implements Runnable{
private Res1 r;
public Output1(Res1 r) {
this.r = r;
}
public void run() {
while(true){
r.out();
}
}
}
public classOptimizeThreadPut {
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}