生产者消费者问题是一个非常典型性的线程交互的问题。
- 使用栈来存放数据
1.1 把栈改造为支持线程安全
1.2 把栈的边界操作进行处理,当栈里的数据是0的时候,访问pull的线程就会等待。 当栈里的数据是200的时候,访问push的线程就会等待 - 提供一个生产者(Producer)线程类,生产随机大写字符压入到堆栈
- 提供一个消费者(Consumer)线程类,从堆栈中弹出字符并打印到控制台
- 提供一个测试类,使两个生产者和三个消费者线程同时运行,
栈:
public class MyStack{
LinkedList list = new LinkedList<>();
//用泛型类定义较好,避免重复定义
// LinkedList list = (LinkedList)
Collections.synchronizedList(linked);
public synchronized void push(T t)
{
while(list.size()>=200)
{
try {
this.wait();
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
// 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或
// notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,
// 锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,
// 而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
this.notifyAll();
list.addLast(t);
}
public synchronized T pull()
{
while(list.size()<=0)
{
try {
this.wait();
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
this.notifyAll();
return list.removeLast();
}
}
测试类:
public class TestStack {
public static void main(String[] args) {
MyStack<Character> ms = new MyStack<>();
Producer []p = new Producer[2];
Consumer []c = new Consumer[3];
for(int i=0;i<p.length;i++)
{
new Producer(ms,"Producer"+i).start();
}
for(int i=0;i<c.length;i++)
{
new Consumer(ms,"Consumer"+i).start();
}
}
消费者类:
public class Consumer extends Thread{
private MyStack<Character> stack;
public Consumer(MyStack<Character> ms,String name)
{
super(name);
this.stack = ms;
}
public void run()
{
while(true) {
char c = stack.pull();
System.out.println(this.getName()+" 弹出 : " +c);
try {
Thread.sleep(1000);
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
生产者类:
public class Producer extends Thread{
private MyStack<Character> stack;
private char character;
public Producer(MyStack<Character> ms,String name)
{
super(name);
this.stack = ms;
}
public void run()
{
while(true)
{
char character = this.getChar();
System.out.printf("%s 压入 %c%n",this.getName(),character);
stack.push(character);
try {
Thread.sleep(1000);
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
private Character getChar()
{
Character character;
while(true)
{
char a = (char)(Math.random()*128);
if(Character.isLetter(a)) {
character = Character.toUpperCase(a);
break;
}
else continue;
}
return character;
}