Java线程通信-生产者消费者问题

java

线程通信示例——生产者消费者问题

这类问题描述了一种情况,假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费.假设仓库中没有产品,则生产者可以将 产品放入仓库,有产品,则停止生产并等待,直到仓库中的产品被消费这取走为止. 如果仓库中放油产品,则消费者可以将产品取走消费,否则停止消费并等待,直到 仓库中再次放入产品为止. 显然,这是一个同步问题,生产者和消费这共享同一资源, 并且生产者和消费这之间彼此依赖,互为条件向前推进.Java提供了3个方法解决了线程间的通信问题,分别是wait() notify() 和 notifyAll()
* (1)调用wait()方法: 使调用该方法的线程释放共享资源的锁,然后从运行状态退出, 进入等待队列,直到被再次唤醒
* (2)调用notify()方法: 唤醒等待队列中第一个等待同一共享资源的线程,并使该线程退出等待,进入就绪状态
* (3)调用notifyAll()方法: 使所有正在等待队列中同一共享资源的线程从等待状态退出,此时优先级最高的那个线程最先执行

/* wait()方法使调用该方法的线程释放共享资源的锁,然后从运行状态退出, 进入等待队列,直到被再次唤醒 */ 

  1 package com.iotek.productconsumerdemo;

2

3 import java.util.LinkedList;

4

5 public class ProductorConsumerDemo {

6

7 /**

8 * 线程通信-wait() notify() notifyAll()

9 * 在现实应用中,很多时候需要让那个多个线程按照i定的次序来访问共享资源,例如经典的生产者消费者问题:

10 * 这类问题描述了这样一种情况,假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者

11 * 将仓库中的产品取走消费,如果仓库中没有产品,在生产者可以将产品放入仓库,否则停止生产并等待,直到

12 * 仓库中的产品被消费这取完为止,如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,

13 * 直到仓库中再次放入产品为止

14 * @param args

15 *

16 */

17 public static void main(String[] args) {

18 Basket basket = new Basket();

19 Productor productor = new Productor(basket);//创建生产者对象

20 Consumer consumer = new Consumer(basket);//创建消费者对象

21 productor.start(); //生产者启动生产

22 consumer.start(); //消费者开始消费

23 }

24

25 }

26

27 class Consumer extends Thread {

28 private Basket basket = null;

29

30 public Consumer(Basket basket) {

31 this.basket = basket;

32 }

33 @Override

34 public void run() {

35 basket.popApple(); //消费者从篮子里取苹果

36 }

37 }

38

39 class Productor extends Thread {

40 private Basket basket = null;

41

42 public Productor(Basket basket) {

43 this.basket = basket;

44 }

45

46 @Override

47 public void run() {

48 basket.pushApple(); // 生产者向篮子里放苹果

49 }

50 }

51

52 // 篮子类,用来存放苹果(需要一个容器来存放,频繁存取,用LinkedList),或者取苹果

53 class Basket {

54 private LinkedList<Apple> basket = new LinkedList<Apple>();

55

56 // 放四轮苹果

57 public synchronized void pushApple() {

58 // synchronized 加锁,放苹果的时候不能取苹果

59 for (int i = 0; i < 20; i++) {

60 Apple apple = new Apple(i);

61 push(apple);

62 }

63 }

64

65 // 取4轮苹果

66 public synchronized void popApple() {

67 for (int i = 0; i < 20; i++) {

68 pop();

69 }

70 }

71

72 // 向篮子里面放苹果 这个方法不对外使用,因此设置为private私有的

73 /* public */private void push(Apple apple) {

74 // 如果篮子里已经有5个苹果了,就等待并通知消费者来消费

75 if (basket.size() == 5) {

76 try {

77 wait();// 等待,并释放当前对象的锁

78 /* 注意!!!调用wait()方法进入等待的线程,必须要通过其他线程调用notify()或notifyAll()方法来唤醒 */

79 } catch (InterruptedException e) {

80 e.printStackTrace();

81 }

82 }

83 // 如果没满5个苹果,那么就继续放苹果

84 try {

85 Thread.sleep(500);// 每隔500ms放一个苹果

86 // sleep()使当前线程每隔设定的休眠时间后,就自动启动线程

87 } catch (InterruptedException e) {

88 e.printStackTrace();

89 }

90 basket.addFirst(apple);// 存放苹果

91 System.out.println("存放:" + apple.toString());

92 notify();// 通知消费者来消费

93 }

94

95 // 从篮子中取苹果

96 /* public */private void pop() {

97 // 当篮子中苹果数为0 的时候就等待并通知生产者来生产

98 if (basket.size() == 0) {

99 try {

100 wait();

101 } catch (InterruptedException e) {

102 e.printStackTrace();

103 }

104 }

105 // 如果篮子中苹果不为0,那么就消费,每隔一定间隔,消费一个苹果

106 try {

107 Thread.sleep(500);

108 } catch (InterruptedException e) {

109 e.printStackTrace();

110 }

111 Apple apple = basket.removeFirst();// 取出一个苹果

112 System.out.println("吃掉:" + apple.toString());

113 notify(); // 通知生产者来生产:notify()方法唤醒等待队列中第一个等待同一共享资源的线程,并使该线程进入就绪状态

114

115 }

116 }

117

118 // 苹果类

119 class Apple {

120 private int id;

121

122 public Apple(int id) {

123 this.id = id;

124 }

125

126 @Override

127 public String toString() {

128 return "苹果:" + (id + 1);

129 }

130 }

以上是 Java线程通信-生产者消费者问题 的全部内容, 来源链接: utcz.com/z/391131.html

回到顶部