问题描述
生产者消费者问题是一个非常典型性的线程交互的问题。
- 使用栈来存放数据
1.1 把栈改造为支持线程安全
1.2 把栈的边界操作进行处理,当栈里的数据是0的时候,访问pull的线程就会等待。 当栈里的数据是200的时候,访问push的线程就会等待 - 提供一个生产者(Producer)线程类,生产随机大写字符压入到堆栈
- 提供一个消费者(Consumer)线程类,从堆栈中弹出字符并打印到控制台
- 提供一个测试类,使两个生产者和三个消费者线程同时运行,结果类似如下 :
程序编写
- MyStack类
描述:
MyStack类用于描述数据的压栈和出栈,这里用泛型来表示
package DuoXianCheng;
import java.util.LinkedList;
public class MyStack<T> {
private LinkedList<T> list;
private int count;
public MyStack() {
list = new LinkedList<>();
count = 0;
}
public synchronized int getSize() {
return count;
}
//压栈
public synchronized void push(T ele) {
while(count >= 200) {
try {
this.wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
list.addLast(ele);
count++;
this.notifyAll();
}
//出栈
public synchronized T pull() {
while(count <= 0) {
try {
this.wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
T res = list.pollLast();
count--;
this.notifyAll();
return res;
}
//查看最后的数据,不取出
public synchronized T peek() {
return list.peekLast();
}
}
- 生产者类
描述:
生产者类用于对英文字母的压栈操作,多线程用实现Runnable接口来实现
package DuoXianCheng;
import java.util.Random;
public class Producer implements Runnable{
private MyStack<Character> stack;
public Producer(MyStack<Character> stack) {
this.stack = stack;
}
public void run() {
while(true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
char c = generateChar();
stack.push(c);
System.out.println("Procucer pushed: " + c + " " + stack.getSize());
}
}
private char generateChar() {
return (char) (new Random().nextInt(26) + 'A');//随机生成英文
}
}
- 消费者类
描述:
生产者类用于出栈操作,多线程也是用实现Runnable接口来实现的
package DuoXianCheng;
public class Consumer implements Runnable{
private MyStack<Character> stack;
public Consumer(MyStack<Character> stack) {
this.stack = stack;
}
public void run() {
while(true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Consumer pulled: " + stack.pull() + " " + stack.getSize());
}
}
}
- 主函数
描述:
两个生产者和三个消费者同时进行
package DuoXianCheng;
/*
1. 使用栈来存放数据
1.1 把栈改造为支持线程安全
1.2 把栈的边界操作进行处理,当栈里的数据是0的时候,访问pull的线程就会等待。
当栈里的数据时200的时候,访问push的线程就会等待
2. 提供一个生产者(Producer)线程类,生产随机大写字符压入到堆栈
3. 提供一个消费者(Consumer)线程类,从堆栈中弹出字符并打印到控制台
4. 提供一个测试类,使两个生产者和三个消费者线程同时运行,结果类似如下 :
*/
public class ShengChanZheXiaoFeiZhe {
public static void main(String[] args) {
MyStack<Character> stack = new MyStack<>();
for (int i = 0; i < 3; i++) {
new Thread(new Producer(stack)).start();//参数为一个带有runnable接口改写了run方法的对象
}
for (int i = 0; i < 2; i++) {
new Thread(new Consumer(stack)).start();
}
}
}