Java线程与并发编程实践----等待通知(生产者消费者问题)线程

Java提供了一套API来支持线程之间的交互。在Object类中提供了一套等待通知的API

 wait()

    notify()

    notifyAll()

    此处要注意的是,绝不要在循环外面调用wait()方法。(单独开一片文章来讨论)


    下面使用消费者与生产者问题来展示以上API的使用:

package xiancheng;

public class PC {

	public static void main(String[] args) {
		Shared s = new Shared();
		Thread t1 = new Thread(new Product(s));
		Thread t2 = new Thread(new Consumer(s));
		t1.start();
		t2.start();
	}
}
class Shared {

	private char c;
	private volatile boolean writeable = true;

	public synchronized void setChar(char ch) {
		while(!writeable) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.c = ch;
		writeable = false;
		notify();
	}

	public synchronized char getChar() {
		while(writeable) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		writeable = true;
		notify();
		return c;
	}
}

class Product implements Runnable{

	private Shared s;
	public Product(Shared s) {
		this.s = s;
	}

	@Override
	public void run() {
		for (char i = 'A'; i < 'Z'; i++) {
			s.setChar(i);
			System.out.println("生产者生产了一个" + i);
		}
	}

}

class Consumer implements Runnable{

	private Shared s;
	public Consumer(Shared s) {
		this.s = s;
	}

	@Override
	public void run() {
		char ch;
		do {
			ch = s.getChar();
			System.out.println("消费者消费了一个" + ch);
		} while (ch != 'Z');
	}
}

打印结果:

消费者消费了一个A
生产者生产了一个A
生产者生产了一个B
消费者消费了一个B
生产者生产了一个C
消费者消费了一个C
生产者生产了一个D
消费者消费了一个D
生产者生产了一个E
消费者消费了一个E
生产者生产了一个F
消费者消费了一个F
生产者生产了一个G
消费者消费了一个G
生产者生产了一个H
消费者消费了一个H
生产者生产了一个I
消费者消费了一个I
生产者生产了一个J
消费者消费了一个J
生产者生产了一个K
消费者消费了一个K
生产者生产了一个L
生产者生产了一个M
消费者消费了一个L
消费者消费了一个M
生产者生产了一个N
消费者消费了一个N
生产者生产了一个O
消费者消费了一个O
生产者生产了一个P
消费者消费了一个P
生产者生产了一个Q
消费者消费了一个Q
生产者生产了一个R
消费者消费了一个R
生产者生产了一个S
消费者消费了一个S
生产者生产了一个T
消费者消费了一个T
生产者生产了一个U
消费者消费了一个U
生产者生产了一个V
消费者消费了一个V
生产者生产了一个W
消费者消费了一个W
生产者生产了一个X
消费者消费了一个X
生产者生产了一个Y
消费者消费了一个Y

很明显第一二行就出现了问题,消费出现在了生产之前,查看代码就知道,生产与消费的顺序并没有错乱,只是打印顺序不对而已,因为唤醒动作是在打印之前,

改进代码如下:

package xiancheng;

public class PC {

	public static void main(String[] args) {
		Shared s = new Shared();
		Thread t1 = new Thread(new Product(s));
		Thread t2 = new Thread(new Consumer(s));
		t1.start();
		t2.start();
	}
}
class Shared {

	private char c;
	private volatile boolean writeable = true;

	public synchronized void setChar(char ch) {
		while(!writeable) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.c = ch;
		writeable = false;
		notify();
	}

	public synchronized char getChar() {
		while(writeable) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		writeable = true;
		notify();
		return c;
	}
}

class Product implements Runnable{

	private final Shared s;
	public Product(Shared s) {
		this.s = s;
	}

	@Override
	public void run() {
		for (char i = 'A'; i < 'Z'; i++) {
			synchronized(s) {
				s.setChar(i);
				System.out.println("生产者生产了一个" + i);
			}
		}
	}

}

class Consumer implements Runnable{

	private final Shared s;
	public Consumer(Shared s) {
		this.s = s;
	}

	@Override
	public void run() {
		char ch;
		do {
			synchronized(s) {
				ch = s.getChar();
				System.out.println("消费者消费了一个" + ch);
			}
		} while (ch != 'Z');
	}
}

运行结果:

生产者生产了一个A
消费者消费了一个A
生产者生产了一个B
消费者消费了一个B
生产者生产了一个C
消费者消费了一个C
生产者生产了一个D
消费者消费了一个D
生产者生产了一个E
消费者消费了一个E
生产者生产了一个F
消费者消费了一个F
生产者生产了一个G
消费者消费了一个G
生产者生产了一个H
消费者消费了一个H
生产者生产了一个I
消费者消费了一个I
生产者生产了一个J
消费者消费了一个J
生产者生产了一个K
消费者消费了一个K
生产者生产了一个L
消费者消费了一个L
生产者生产了一个M
消费者消费了一个M
生产者生产了一个N
消费者消费了一个N
生产者生产了一个O
消费者消费了一个O
生产者生产了一个P
消费者消费了一个P
生产者生产了一个Q
消费者消费了一个Q
生产者生产了一个R
消费者消费了一个R
生产者生产了一个S
消费者消费了一个S
生产者生产了一个T
消费者消费了一个T
生产者生产了一个U
消费者消费了一个U
生产者生产了一个V
消费者消费了一个V
生产者生产了一个W
消费者消费了一个W
生产者生产了一个X
消费者消费了一个X
生产者生产了一个Y
消费者消费了一个Y

原文地址:http://blog.51cto.com/12222886/2060728

时间: 2024-10-13 11:30:50

Java线程与并发编程实践----等待通知(生产者消费者问题)线程的相关文章

Java线程与并发编程实践----锁框架

Java.util.concurrent.locks包提供了一个包含多种接口和类的框架,它 针对条件进行加锁和等待.不同于对象的内置加锁同步以及java.lang.Object的等 待/通知机制,包含锁框架的并发工具类通过轮询锁.显示等待及其它方式改善这种 机制. 锁框架包含了经常使用的锁.重入锁.条件.读写锁以及冲入读写锁等类别. 一.锁(Lock) Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作.此实 现允许更灵活的结构,可以具有差别很大的属性,可以

Java线程与并发编程实践----同步器(交换器、信号量)

一.交换器 交换器提供了一个线程之间能够交换对象的同步点.每个线程都会往这个 交换器的exchange()方法传入一些对象,匹配伙伴线程,同时接受伙伴对象作为返 回值.java.util.conurrent.Exchange<V>实现了交换器. 下面是一个代码小实例: import java.util.concurrent.Exchanger;   import java.util.concurrent.ExecutorService;   import java.util.concurren

超强图文|并发编程【等待/通知机制】就是这个feel~

你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough 现陆续将Demo代码和技术文章整理在一起 Github实践精选 ,方便大家阅读查看,本文同样收录在此,觉得不错,还请Star 并发编程为什么会有等待通知机制 上一篇文章说明了 Java并发死锁解决思路 , 解决死锁的思路之一就是 破坏请求和保持条件, 所有柜员都要通过唯一的账本管理员一次性拿到所有

并发编程—— 阻塞队列和生产者-消费者模式

Java并发编程实践 目录 并发编程—— ConcurrentHashMap 并发编程—— 阻塞队列和生产者-消费者模式 概述 第1部分 为什么要使用生产者和消费者模式 第2部分 什么是生产者消费者模式 第3部分 代码示例 第1部分 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样的道理,如果消费者的处理能力大于生产者,那么消费

[Java 并发] Java并发编程实践 思维导图 - 第二章 线程安全性

根据<Java并发编程实践>一书整理的思维导图.

Java线程与并发编程实践----并发工具类与Executor框架

java5之前,我们使用诸如synchronized,wait(),notify()方法对线程的操作属于对 底层线程的操作,这样会出现很多的问题: 低级的并发原语,比如synchronized,wait(),notify()经常难以正确使用.误用会导致 竞态条件,线程饿死,死锁等风险. 泰国依赖synchronized会影响程序性能以及程序的可扩展性 开发者经常需要高级线程结构,如线程池,信号量.java对底层线程的操作不包含这些结. 为解决这些问题,java5引入并发工具类,该工具类主要有下面

Java并发编程实践读书笔记(5) 线程池的使用

Executor与Task的耦合性 1,除非线程池很非常大,否则一个Task不要依赖同一个线程服务中的另外一个Task,因为这样容易造成死锁: 2,线程的执行是并行的,所以在设计Task的时候要考虑到线程安全问题.如果你认为只会在单任务线程的Executor中运行的话,从设计上讲这就已经耦合了. 3,长时间的任务有可能会影响到其他任务的执行效率,可以让其他线程在等待的时候限定一下等待时间.不要无限制地等待下去. 确定线程池的大小 给出如下定义: 要使CPU达到期望的使用率,线程池的大小应设置为:

java线程与并发编程实践(一)

一.给出线程的定义     线程就是一条在程序代码中独立执行的路径 二.给出runnable的定义 一个runnable就是一段封装在对象中的代码序列,它的类实现了runnable接口 三.Thread类和runnable接口完成了什么? 类Thread提供了一个底层操作系统的线程架构的统一接口.Runnable接口为关联了Thread对象的线程提供了执行代码. 四.指出创建一个Runnable对象的两种方式? 创建一个实现Runnable接口的匿名类或者lambda表达式 Runnable r

Java线程与并发编程实践----额外的并发工具类

一.并发集合 java.util包下提供了很多的集合类,如ArrayList.TreeSet.HashMap,但是这些 集合都是非线程安全的,并且对于单列集合的迭代器,采用的是快速失败机制,当正在迭代 遍历的集合被其它线程修改时,便会抛出 java.util.ConcurrentModificationException. 这显然对于多线程操作的集合是十分不方便的,但早Colections这个工具类中有方法可以返回 线程安全的集合,然而这种集合对于高并发环境,性能十分低下. 于是,java.ut