java多线程之生产消费问题

<pre name="code" class="java">一:多线程中生产者,消费者问题
生产者生产产品,消费者消费产品,无产品的时候,消费者无法消费,有产品的时候生产者不需要生产。(始终只有一个产品的情况)
 
生产消费模型中存在的问题:
1,初始状态下,无产品,消费者不能消费
2,当有产品存在时,生产者不需要生产,等待消费者消费之后再行生产
3,当有产品存在时,消费者可以进行消费,消费之后产品不再存在,需要等待生产者再进行生产
下面的例子程序错误的实行了一个简单生产者/消费者的问题。它由四个类组成:Q,设法获得同步的序列;Producer,产生排队的线程对象;Consumer,消费序列的线程对象;以及PC,创建单个Q,Producer,和Consumer的小类。

 
<pre name="code" class="java">class Q {
    int n;
    synchronized int get() {
        System.out.println("Got: " + n);
        return n;
    }
    synchronized void put(int n) {
        this.n = n;
        System.out.println("Put: " + n);
    }
}
class Producer implements Runnable {
    Q q;
    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }
    public void run() {
        int i = 0;
        while(true) {
            q.put(i++);
        }
    }
}
class Consumer implements Runnable {
    Q q;
    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }
    public void run() {
        while(true) {
           q.get();
        }
    }
}
class PC {
    public static void main(String args[]) {
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
        System.out.println("Press Control-C to stop.");
    }
}


 

虽然在Q类中,put和get方法加了同步锁,但是并不能阻止生产消费错误的产生。如下输出:

Put: 0 count:1
Press Control-C to stop.
Got: 0 count: 1
Put: 1 count:1
Got: 1 count: 1
Got: 1 count: 0
Put: 2 count:0
Put: 3 count:1
Got: 3 count: 1
Put: 4 count:1
Got: 4 count: 1
Put: 5 count:1
Got: 5 count: 1
Put: 6 count:1
Got: 6 count: 1
Put: 7 count:1
Got: 7 count: 1
Got: 7 count: 0
当消费者线程连续执行时,消费者存在两次消费同一个产品的问题。

解决办法:使用信号量semaphore的方式来解决

1,在Q类中设置一个计数器int count = 0;生产者线程生产一个产品count+1,消费者线程消费一个产品count-1,使count在0和1之间变化

package thread;

class Q {
    int n=0;
    int count = 0;
    synchronized int get() {
    	if(count>0){
    		System.out.println("Got: " + n+" count: "+count);
    		count--;
    		return n;
    	}else
    		return -1;
    }
    synchronized void put(int n) {
    	if(count<1){
    		this.n = n;
        	count++;
        	System.out.println("Put: " + n+" count:"+count);
    	}
    }
}
class Producer implements Runnable {
    Q q;
    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }
    public void run() {
        int i = 0;
        while(true) {
            q.put(i++);
            try {
				Thread.sleep(1*1000);
			} catch (InterruptedException e){ 
				e.printStackTrace();
			}
        }
    }
}
class Consumer implements Runnable {
    Q q;
    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }
    public void run() {
        while(true) {
           q.get();
           try {
				Thread.sleep(1*1000);
			} catch (InterruptedException e){ 
				e.printStackTrace();
			}
        }
    }
}
class PC {
    public static void main(String args[]) {
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
        System.out.println("Press Control-C to stop.");
    }
}
使用该方法时,生产消费线程一直在执行,只是会产生无输出结果的方法调用。

2,使用wait和notify方法来阻塞、唤醒线程

在Q类中设置boolean product = false信号量,当消费者起初企图消费时,使用wait方法阻塞消费者线程,并唤醒生产者线程进行生产,

当生产线程生产之后,唤醒消费者线程

package thread;

class Q {
    int n=0;
    boolean product = false;
    synchronized int get() {
    	if(!product)
    		try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
    	product = false ;
		System.out.println("Got: " + n);
		notify();
		return n;
    }
    synchronized void put(int n) {
    	if(product)
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		this.n = n;
		product=true;
		notify();
		System.out.println("Put: " + n+" count:");
    }
}
class Producer implements Runnable {
    Q q;
    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }
    public void run() {
        int i = 0;
        while(true) {
            q.put(i++);
            try {
				Thread.sleep(1*1000);
			} catch (InterruptedException e){ 
				e.printStackTrace();
			}
        }
    }
}
class Consumer implements Runnable {
    Q q;
    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }
    public void run() {
        while(true) {
           q.get();
           try {
				Thread.sleep(1*1000);
			} catch (InterruptedException e){ 
				e.printStackTrace();
			}
        }
    }
}
class PC {
    public static void main(String args[]) {
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
        System.out.println("Press Control-C to stop.");
    }
}
该方法会阻塞、唤醒线程,不同于上一种方法,输出结果:

Put: 0 count:
Press Control-C to stop.
Got: 0
Put: 1 count:
Got: 1
Put: 2 count:
Got: 2
Put: 3 count:
Got: 3
Put: 4 count:
Got: 4
Put: 5 count:
Got: 5
Put: 6 count:
Got: 6
Put: 7 count:
Got: 7



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值