多线程中的生产者消费者问题
线程安全问题
在多线程编程过程中,时常会出现多个线程同时操作同一资源,导致了线程的不安全,此时可以用队列加锁的机制来解决。
使用synchronized关键词可以对一个方法或者一段代码块进行加锁,只有当锁定的线程执行完以后,其它线程才可以进行操作,从而解决线程同步问题,大大加强了线程的安全性。
生产者消费者问题的提出
但是很多时候线程之间仅仅同步是不够的,还需要不同线程之间的消息传递通信,因此,提出了生产者消费者问题。
问题的提出:
对于生产者,在生产产品之前需要通知消费者等待,当生产完需要通知消费者消费。
对于消费者,在消费完以后需要通知生产者生产产品,当产品为空时需要等待。
当我们把生产者和消费者当做两个线程来看待时,就需要线程之间的通信才能解决上面的问题了。
生产者消费者问题中需要用到的方法
方法名 | 方法说明 |
---|---|
wait() | 使线程处于等待状态并且释放锁,直到其它线程通知 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒处于等待状态的线程 |
notifyAll() | 唤醒同一对象上所有调用wait()方法的线程,优先级别高的线程优先调度 |
生产者消费者问题的解决方法
- 管程法
创建一个缓冲区,生产者和消费者对缓冲区中的资源进行调配操作。
public class TestPC {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
new Productor(synContainer).start();
new Consumer(synContainer).start();
}
}
//生产者
class Productor extends Thread{
SynContainer synContainer;
public Productor(SynContainer synContainer){
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 1; i < 100; i++) {
synContainer.push(new Chicken(i));
System.out.println("生产了第"+i+"只鸡");
}
}
}
//消费者
class Consumer extends Thread{
SynContainer synContainer;
public Consumer(SynContainer synContainer){
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 1; i < 100; i++) {
System.out.println("消费了第"+synContainer.pop().id+"只鸡");
}
}
}
//产品(KFC)
class Chicken{
int id;
public Chicken(int id){
this.id = id;
}
}
//缓冲区
class SynContainer{
//容器
Chicken[] chickens = new Chicken[10];
//容器计数器
int count = 0;
//生产者生产产品放入容器
public synchronized void push(Chicken chicken){
//判断缓冲区是否已满,如果满了,通知消费者消费
if(count == chickens.length){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
chickens[count] = chicken;
count++;
this.notify();
}
//消费者从容器取出产品
public synchronized Chicken pop(){
//判断缓冲区是否为空。如果为空,通知生产者生产
if(count == 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
Chicken chicken = chickens[count];
this.notify();
return chicken;
}
}
- 信号灯法
通过一个信号灯标志来使线程等待或者唤醒线程。
public class TestPC {
public static void main(String[] args) {
TV tv = new TV();
new Player(tv).start();
new Watcher(tv).start();
}
}
//生产者(演员)
class Player extends Thread{
TV tv;
public Player(TV tv){
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.play("Java");
}
}
}
//消费者(观众)
class Watcher extends Thread{
TV tv;
public Watcher(TV tv){
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.watch();
}
}
}
//产品(节目)
class TV{
String voice; //节目
boolean flag = true; //是否存在节目
//演员表演
public synchronized void play(String voice){
if(!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演员表演了:"+voice);
this.notifyAll();
this.voice = voice;
this.flag = !this.flag;
}
//观众观看
public synchronized void watch(){
if(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
System.out.println("观众观看了:"+voice);
this.flag = !this.flag;
}
}