线程通信经典例题之消费者与生产者问题:
问题:
我们的生产者(productor)将我们的产品交给我们的店员(Clerk),而我们的消费者将从店员处取走产品,店员一次只能是持有固定数量的产品(比如我们在这里就设定为:20),也就是当我们的店员手中持有的产品超过20时,我们的店员就会让我们的生产者停止生产,接下来要等到我们的消费者来买走一些产品之后我们的店员店里有了空位之后我们的再告诉我们的生产者开始生产商品,如果我们的店里的产品买完了的话,那么我们的店员就会让我们的消费者停一下
分析:
这个问题中是否有多线程:
- 是,我们的消费者线程和我们的生产者线程
这个问题中是否有共享数据?
- 是,店员(或者说产品就是我们的共享数据)
- 这个时候我们的多个线程之间有了共享数据,这个时候也就是会有线程的安全问题
如何解决线程的安全问题?
- 通过我们的同步机制(也就是三种方式(同步代码块.同步方法,Lock锁的方式),这里我们也可以说是两种方式(synchronized,Lock))
是否涉及到线程的通信?
是,当我们的店中产品为20之后我们就会让我们的生产者线程wait一下,让我们的消费者线程先执行,小于20之后再开始生产,当我们的店中的产品为零时我们就要让我们的,消费者线程等一下
package 多线程.线程通信;
//售货员
class Clerk{
private int productCount; //这里默认为0
public synchronized void product(){
notify(); //我们进入同步机制之后就要唤醒一下
if(productCount<20){
productCount++;
System.out.println(Thread.currentThread().getName()+"正在生产第"+productCount+"件产品");
}else {
try {
//如果我们的产品数量等于二十,就让我们的生产者等一等
wait();
}catch(InterruptedException e){//这里抛出了一个线程中断异常
e.printStackTrace();
}
}
}
public synchronized void consume(){
notify(); //我们进入同步机制之后就要唤醒一下
if(productCount>0){
System.out.println(Thread.currentThread().getName()+"正在消费第"+productCount+"件产品");
productCount--;
}else {
try {
wait(); //如果我们的产品没有了,这个时候我们就要让消费者等一下
}catch(InterruptedException e){ //这里抛出一个线程中断异常
e.printStackTrace();
}
}
}
}
//生产者线程
class Producer extends Thread{
private Clerk clerk;
public Producer(Clerk clerk){
this.clerk=clerk;
}
public void run(){
System.out.println(Thread.currentThread().getName()+"开始生产产品---");
while(true){
try {
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
clerk.product(); //调用了我们的生产方法
}
}
}
//消费者
class Consumer extends Thread{
private Clerk clerk;
public Consumer(Clerk clerk){
this.clerk=clerk;
}
public void run(){
System.out.println(Thread.currentThread().getName()+"开始消费产品---");
while(true){
try {
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
clerk.consume(); //调用了我们的消费方法
}
}
}
public class Text {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Producer p1 = new Producer(clerk);
p1.setName("生产者1");
Consumer c1 = new Consumer(clerk);
c1.setName("消费者1");
p1.start();
c1.start();
}
}