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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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


以上是关于Java线程与并发编程实践----等待通知(生产者消费者问题)线程的主要内容,如果未能解决你的问题,请参考以下文章

Java 并发编程 -- 并发编程线程基础(线程创建与运行线程通知与等待join / sleep / yield方法线程中断线程上下文切换死锁守护线程与用户线程ThreadLocal)

Java 并发编程 -- 并发编程线程基础(线程创建与运行线程通知与等待join / sleep / yield方法线程中断线程上下文切换死锁守护线程与用户线程ThreadLocal)

java并发编程实践学习--对象的组合

Java并发编程(04):线程间通信,等待/通知机制

Java并发编程(04):线程间通信,等待/通知机制

Day826.Java多线程等待&通知机制 -Java 并发编程实战