Java---19---多线程:生产者和消费者

生产者和消费者问题是多线程通信的经典问题。这类问题描述了这样一种情况:假设有一个仓库,用来存储产品,有生产者负责生产产品,有消费者负责消费。生产者生产的产品存放在仓库之中,消费者从仓库之中取出产品。显然这是一个同步问题,生产者和消费者共享同一资源,并且生产者和消费者之间彼此依赖,互为条件向前推进。那么,该如何编写代码来实现呢?

class Resource {
	private String name;
	private String sex;
	private boolean flag = false;

	public synchronized void set(String name, String sex) {
		if (flag == true) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.name = name + "--" + sex;
		System.out.println(Thread.currentThread().getName() + "--生产者--"
				+ this.name);
		flag = true;
		notify();
	}

	public synchronized void out() {
		if (flag == false) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName() + "---消费者---"
				+ this.name);
		flag = false;
		notify();
	}
}

class Producer implements Runnable {
	private Resource resource;
	private int num = 0;

	Producer(Resource resource) {
		this.resource = resource;
	}

	public void run() {
		while (true) {
			if (num == 1) {

				resource.set("丽丽", "女女女");
			} else {
				resource.set("mike", "man");
			}
			num = ++num % 2;
		}
	}
}

class Consumer implements Runnable {
	private Resource resource;

	Consumer(Resource resource) {
		this.resource = resource;
	}

	public void run() {
		while (true) {
			resource.out();
		}
	}
}

class Communicate {
	public static void main(String[] args) {
		Resource resource = new Resource();
		Producer pro = new Producer(resource);
		Consumer con = new Consumer(resource);
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(con);

		t1.start();
		t2.start();

	}
}

这个例子已经实现了生产一个就消费一个,其实这个例子就是上一篇文章中的例子,只是将代码略作优化。

但是还有一个问题,这个例子只是一个线程用来生产,一个线程用来消费,那如果多加几个线程呢?

那我们多加上几个线程试试。

class Resource {
	private String name;
	private String sex;
	private boolean flag = false;

	public synchronized void set(String name, String sex) {
		if (flag == true) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.name = name + "--" + sex;
		System.out.println(Thread.currentThread().getName() + "--生产者--"
				+ this.name);
		flag = true;
		notify();
	}

	public synchronized void out() {
		if (flag == false) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName() + "---消费者---"
				+ this.name);
		flag = false;
		notify();
	}
}

class Producer implements Runnable {
	private Resource resource;
	private int num = 0;

	Producer(Resource resource) {
		this.resource = resource;
	}

	public void run() {
		while (true) {
			if (num == 1) {

				resource.set("丽丽", "女女女");
			} else {
				resource.set("mike", "man");
			}
			num = ++num % 2;
		}
	}
}

class Consumer implements Runnable {
	private Resource resource;

	Consumer(Resource resource) {
		this.resource = resource;
	}

	public void run() {
		while (true) {
			resource.out();
		}
	}
}

class Communicate {
	public static void main(String[] args) {
		Resource resource = new Resource();
		Producer pro = new Producer(resource);
		Consumer con = new Consumer(resource);
		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();
	}
}

在打印结果中我们发现会有这种情况:

Thread-1--生产者--mike--man

Thread-0--生产者--mike--man

Thread-2---消费者---mike--man

还可能会发生生产一个而消费两个的情况。出现的原因在 wait()这,就不过多的解释了。

只需要将判断flag 的if 改为while 同时将notify改为notifyAll() 就ok。

修改完如下:

class Resource {
	private String name;
	private String sex;
	private boolean flag = false;

	public synchronized void set(String name, String sex) {
		while (flag == true) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.name = name + "--" + sex;
		System.out.println(Thread.currentThread().getName() + "--生产者--"
				+ this.name);
		flag = true;
		notifyAll();
	}

	public synchronized void out() {
		while (flag == false) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName() + "---消费者---"
				+ this.name);
		flag = false;
		notifyAll();
	}
}

class Producer implements Runnable {
	private Resource resource;
	private int num = 0;

	Producer(Resource resource) {
		this.resource = resource;
	}

	public void run() {
		while (true) {
			if (num == 1) {

				resource.set("丽丽", "女女女");
			} else {
				resource.set("mike", "man");
			}
			num = ++num % 2;
		}
	}
}

class Consumer implements Runnable {
	private Resource resource;

	Consumer(Resource resource) {
		this.resource = resource;
	}

	public void run() {
		while (true) {
			resource.out();
		}
	}
}

class Communicate {
	public static void main(String[] args) {
		Resource resource = new Resource();
		Producer pro = new Producer(resource);
		Consumer con = new Consumer(resource);
		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();
	}
}
时间: 2024-11-05 12:24:47

Java---19---多线程:生产者和消费者的相关文章

JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题

JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序员杜鹏程的博客:http://blog.csdn.net/m366917 我们来继续学习多线程 Lock锁的使用 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock Lock void lock():获取锁 v

Java多线程--生产者与消费者问题

说明 Java中,线程之间的通信主要是由java.lang.Object类提供的wait.notify和notifyAll这3个方法来完成: ①对象的wait方法被调用后,线程进入对象的等待队列中,并释放对象锁,其它线程可以竞争使用此对象锁:sleep方法使得一个线程进入睡眠状态,但是线程所占有的资源并没有释放. ②当对象的notify方法被调用,该方法会从对象的等待队列中随机取出一个线程来唤醒:notifyAll是唤醒等待队列中所有线程,这些线程会与其它正在执行的线程共同竞争对象锁. ③wai

多线程-生产者与消费者(存储数据与打印数据)

无线程同步: 存储数据: 1 public class Storage { 2 int data; 3 4 public int getData() { 5 return data; 6 } 7 8 public void setData(int data) { 9 this.data = data; 10 } 11 12 } 产生数据: 1 public class Counter implements Runnable { 2 private Storage storage; 3 4 pub

Java中的生产者、消费者问题

Java中的生产者.消费者问题描述: 生产者-消费者(producer-consumer)问题, 也称作有界缓冲区(bounded-buffer)问题, 两个进程共享一个公共的固定大小的缓冲区(仓库). 其中一个是生产者, 用于将产品放入仓库: 另外一个是消费者, 用于从仓库中取出产品消费. 问题出现在当仓库已经满了, 而此时生产者还想向其中放入一个新的产品的情形, 其解决方法是让生产者此时进行等待, 等待消费者从仓库中取走了一个或者多个产品后再去唤醒它. 同样地, 当仓库已经空了, 而消费者还

多线程——生产者和消费者的问题

生产者和消费者问题的产生 生产者和消费者是指俩个不同的线程对象,操作统一资源的情况:生产者负责生产数据,消费者负责消费数据,生产者每生产完一组数据后,消费者  消费一组数据, Object对多线程的支持:  wait();等待被唤醒  notify();唤醒  notifyAll();唤醒所有 sleep()和wait()的区别: sleep()属于Thread类,类似于一个闹钟,只持续一定时间.wait()属于Object类,需要被notify()唤醒,如果不唤醒就会一直等待下去 具体案例如下

java多线程:生产者和消费者模式(wait-notify) : 单生产和单消费

单生产者 package com.example.t.pc; import java.util.List; //生产者 public class P { private List list; public P(){ } public P(List list){ this.list = list; } public void add(){ while(true){ synchronized (list){ try { System.out.println("3s----------------&q

多线程——生产者和消费者(四)

通过前面三篇博客的介绍,基本上对Java的多线程有了一定的了解了,然后这篇博客根据生产者和消费者的模型来介绍Java多线程的一些其他知识. 我们这里的生产者和消费者模型为: 生产者Producer 生产某个对象(共享资源),放在缓冲池中,然后消费者从缓冲池中取出这个对象.也就是生产者生产一个,消费者取出一个.这样进行循环.   第一步:我们先创建共享资源的类 Person,它有两个方法,一个生产对象,一个消费对象 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

多线程生产者、消费者模式中,如何停止消费者?多生产者情况下对“毒丸”策略的应用。

生产者.消费者模式是多线程中的经典问题.通过中间的缓冲队列,使得生产者和消费者的速度可以相互调节. 对于比较常见的单生产者.多消费者的情况,主要有以下两种策略: 通过volatile boolean producerDone =false 来标示是否完成.生产者结束后标示为true, 消费者轮询这个变量来决定自己是否退出. 这种方式对producerDone产生比较大的争用,实现起来也有诸多问题需要考虑. 比较经典的"毒丸"策略,生产者结束后,把一个特别的对象:"毒丸&quo

2015阿里巴巴校招附加题:多线程-生产者和消费者

今天参加了阿里2015校招实习生的笔试. 选择题部分确实有水平,由于基础一般再加上没做准备,打得一塌糊涂,目测已经阵亡了,不过附加题的最后一个还是很基础的,关于java的多线程中的生产者和消费者的问题,在此感谢@绝影. 题目: 有个篮子,一个人不停地往里面放苹果,另一个不停地从里面拿出来苹果,篮子最多能放5个苹果,苹果数量无限.用Java模拟实现. 实现过程: 主类: class ProducerConsumer { public static void main(String[] args)

Java实现多线程生产者消费模型及优化方案

生产者-消费者模型是进程间通信的重要内容之一.其原理十分简单,但自己用语言实现往往会出现很多的问题,下面我们用一系列代码来展现在编码中容易出现的问题以及最优解决方案. /* 单生产者.单消费者生产烤鸭 */class Resource { private String name; private int count = 1; //计数器,记录有多少只烤鸭被生产及消费 private boolean flag = false; //停止标记 public synchronized void set