生产者消费者问题JAVA代码说明文档
一、生产者消费者问题说明
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。参考地址
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。参考地址
二、问题解决
解决核心:
①生产者—消费者之间的同步关系表现为: 一旦缓冲池中所有缓冲区均装满产品时,生产者必须等待消费者提供空缓冲区;一旦缓冲池中所有缓冲区全为空时,消费者必须等待生产者提供缓冲区。
②生产者—消费者之间还有互斥关系: 由于缓冲池是临界资源,所以任何进程在对缓冲区进行存取操作时都必须和其他进程互斥进行。
伪代码:
semaphore mutex=1;
semaphore empty=n;
semaphore full=0;
producer ()
{
while(1)
{
produce an item in nextp;
P(empty);
P(mutex);
add nextp to buffer;
V(mutex);
V(full);
}
}
consumer ()
{
while(1)
{
P(full);
P(mutex);
remove an item from buffer;
V(mutex);
V(empty) ;
consume the item;
}
}
JAVA代码:
public class Producer extends Thread implements Runnable {
private Cache cache;
public Producer(Cache cache){
this.cache = cache;
}
@Override
public void run() {
while (true){
try{
cache.produce();
Thread.sleep(cache.produce_speed);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
public class Consumer extends Thread implements Runnable{
private Cache cache;
public Consumer(Cache cache){
this.cache = cache;
}
@Override
public void run() {
while (true){
try{
cache.consume();
Thread.sleep(cache.consume_speed);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Cache {
public int SIZE = 100;
public int count;
public Lock lock;
private Condition notFull;
private Condition notEmpty;
int produce_speed = 0;
int consume_speed = 0;
public String producer_print = "";
public String consumer_print = "";
public Cache(){
this.count = 0;
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
this.notFull = lock.newCondition();
}
public void produce(){
try {
lock.lock();
while (count == SIZE) {
try {
System.out.println("容器已满,生产者阻塞");
notFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;
producer_print = "生产者生产了一个,当前数量为:" + count +"\n"+ "生产者线程为:" + Thread.currentThread().getName();
System.out.println(producer_print);
notEmpty.signal();
}finally {
lock.unlock();
}
}
public void consume(){
try {
lock.lock();
while (count == 0) {
try {
System.out.println("容器已满,消费者阻塞");
notEmpty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
consumer_print = "消费者消费了一个,当前数量为:" + count + '\n'+ "消费者线程为:" + Thread.currentThread().getName();
System.out.println(consumer_print);
notFull.signal();
}finally {
lock.unlock();
}
}
}
import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main {
static String Producer_print ;
static String Consumer_print ;
static String Cache_print ;
public static int is_begin = 0;
public static int is_end = 0;
private static long sleep_millis;
private static int is_start = 0;
static int producerCount = 0;
static int consumerCount = 0;
public static void main(String[] args) throws InterruptedException {
Cache cache = new Cache();
Producer p = new Producer(cache);
Consumer c = new Consumer(cache);
JFrame jFrame = new JFrame();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(1300,700);
jFrame.setTitle("生产者消费者问题");
Font label_font = new Font("Monospaced",Font.BOLD,20);
Font Panel_font = new Font("Monospaced",Font.BOLD,18);
JPanel panel = new JPanel();
panel.setLayout(null);
jFrame.add(panel);
JPanel panel_attribute = new JPanel();
panel_attribute.setLayout(null);
panel_attribute.setBounds(new Rectangle(60,60,400,250));
panel_attribute.setBorder(BorderFactory.createTitledBorder(null,"设置基本属性", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION,Panel_font));
panel.add(panel_attribute,BorderLayout.EAST);
JPanel panel_print = new JPanel();
panel_print.setLayout(null);
panel_print.setBounds(new Rectangle(500,60,700,500));
panel_print.setBorder(BorderFactory.createTitledBorder(null,"线程运行监控",TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION,Panel_font));
panel.add(panel_print,BorderLayout.EAST);
JLabel buffer_label = new JLabel("缓冲区容量:");
buffer_label.setBounds(40,55,200,40);
buffer_label.setForeground(Color.black);
buffer_label.setFont(label_font);
jFrame.getContentPane().add(buffer_label);
panel_attribute.add(buffer_label);
JLabel Producer_label = new JLabel("生产者数量:");
Producer_label.setBounds(40,85,200,40);
Producer_label.setForeground(Color.black);
Producer_label.setFont(label_font);
jFrame.getContentPane().add(Producer_label);
panel_attribute.add(Producer_label);
JLabel Consumer_label = new JLabel("消费者数量:");
Consumer_label.setBounds(40,115,200,40);
Consumer_label.setForeground(Color.BLACK);
Consumer_label.setFont(label_font);
jFrame.getContentPane().add(Consumer_label);
panel_attribute.add(Consumer_label);
JLabel Producer_speed_label = new JLabel("生产者生产速度:");
Producer_speed_label.setBounds(40,145,200,40);
Producer_speed_label.setForeground(Color.BLACK);
Producer_speed_label.setFont(label_font);
jFrame.getContentPane().add(Producer_speed_label);
panel_attribute.add(Producer_speed_label);
JLabel Consumer_speed_label = new JLabel("消费者消耗速度:");
Consumer_speed_label.setBounds(40,175,200,40);
Consumer_speed_label.setForeground(Color.BLACK);
Consumer_speed_label.setFont(label_font);
jFrame.getContentPane().add(Consumer_speed_label);
panel_attribute.add(Consumer_speed_label);
JComboBox buffer_ComboBox = new JComboBox();
buffer_ComboBox.addItem(10);
buffer_ComboBox.addItem(100);
buffer_ComboBox.addItem(1000);
buffer_ComboBox.addItem(10000);
buffer_ComboBox.setBounds(170,64,140,26);
panel_attribute.add(buffer_ComboBox);
JComboBox Producer_ComboBox = new JComboBox();
Producer_ComboBox.addItem(1);
Producer_ComboBox.addItem(2);
Producer_ComboBox.addItem(4);
Producer_ComboBox.addItem(8);
Producer_ComboBox.addItem(16);
Producer_ComboBox.addItem(32);
Producer_ComboBox.setBounds(170,94,140,26);
panel_attribute.add(Producer_ComboBox);
JComboBox Consumer_ComboBox = new JComboBox();
Consumer_ComboBox.addItem(1);
Consumer_ComboBox.addItem(2);
Consumer_ComboBox.addItem(4);
Consumer_ComboBox.addItem(8);
Consumer_ComboBox.addItem(16);
Consumer_ComboBox.addItem(32);
Consumer_ComboBox.setBounds(170,124,140,26);
panel_attribute.add(Consumer_ComboBox);
JComboBox Producer_speed_ComboBox = new JComboBox();
Producer_speed_ComboBox.addItem(10);
Producer_speed_ComboBox.addItem(100);
Producer_speed_ComboBox.addItem(1000);
Producer_speed_ComboBox.addItem(10000);
Producer_speed_ComboBox.setBounds(210,154,140,26);
panel_attribute.add(Producer_speed_ComboBox);
JComboBox Consumer_speed_ComboBox = new JComboBox();
Consumer_speed_ComboBox.addItem(10);
Consumer_speed_ComboBox.addItem(100);
Consumer_speed_ComboBox.addItem(1000);
Consumer_speed_ComboBox.addItem(10000);
Consumer_speed_ComboBox.setBounds(210,184,140,26);
panel_attribute.add(Consumer_speed_ComboBox);
JButton begin_button = new JButton("开始");
begin_button.setLocation(60, 360);
begin_button.setSize(200, 40);
begin_button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
is_begin = 1;
is_end = 0;
}
});
jFrame.getContentPane().add(begin_button);
panel.add(begin_button);
JButton cease_button = new JButton("暂停");
cease_button.setLocation(60, 410);
cease_button.setSize(200, 40);
cease_button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
is_begin = 0;
is_end = 1;
}
});
jFrame.getContentPane().add(cease_button);
panel.add(cease_button);
JButton exit_button = new JButton("结束");
exit_button.setLocation(60, 460);
exit_button.setSize(200, 40);
exit_button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
jFrame.getContentPane().add(exit_button);
panel.add(exit_button);
JLabel Thread_buffer_label = new JLabel("生产者线程:");
Thread_buffer_label.setBounds(35,33,200,40);
Thread_buffer_label.setForeground(Color.black);
Thread_buffer_label.setFont(label_font);
jFrame.getContentPane().add(Thread_buffer_label);
panel_print.add(Thread_buffer_label);
JLabel Thread_Producer_label = new JLabel("消费者线程:");
Thread_Producer_label.setBounds(245,33,200,40);
Thread_Producer_label.setForeground(Color.black);
Thread_Producer_label.setFont(label_font);
jFrame.getContentPane().add(Thread_Producer_label);
panel_print.add(Thread_Producer_label);
JLabel Thread_Consumer_label = new JLabel("缓冲区数量:");
Thread_Consumer_label.setBounds(455,33,200,40);
Thread_Consumer_label.setForeground(Color.BLACK);
Thread_Consumer_label.setFont(label_font);
jFrame.getContentPane().add(Thread_Consumer_label);
panel_print.add(Thread_Consumer_label);
JTextArea Thread_Producer_TextArea = new JTextArea();
Thread_Producer_TextArea.setText(Producer_print+Thread_Producer_TextArea.getText());
Thread_Producer_TextArea.setText("");
Thread_Producer_TextArea.setBounds(35,70,200,400);
panel_print.add(Thread_Producer_TextArea);
JTextArea Thread_Consumer_TextArea = new JTextArea();
Thread_Consumer_TextArea.setText(Consumer_print+'\n'+Thread_Consumer_TextArea.getText());
Thread_Consumer_TextArea.setText("");
Thread_Consumer_TextArea.setBounds(245,70,200,400);
panel_print.add(Thread_Consumer_TextArea);
JTextArea Thread_cache_TextArea = new JTextArea();
Thread_cache_TextArea.setText(Cache_print+"\n"+Thread_cache_TextArea.getText());
Thread_cache_TextArea.setText("");
Thread_cache_TextArea.setBounds(455,70,200,400);
panel_print.add(Thread_cache_TextArea);
jFrame.setContentPane(panel);
jFrame.setVisible(true);
while(true){
Producer_print = cache.producer_print;
Consumer_print = cache.consumer_print;
Cache_print = "缓存区的容量为:"+cache.count;
cache.SIZE = (Integer)buffer_ComboBox.getSelectedItem();
producerCount = (Integer)Producer_ComboBox.getSelectedItem();
consumerCount = (Integer)Consumer_ComboBox.getSelectedItem();
cache.produce_speed = (Integer)Producer_speed_ComboBox.getSelectedItem();
cache.consume_speed = (Integer)Consumer_speed_ComboBox.getSelectedItem();
Thread_Producer_TextArea.setText(Producer_print+"\n"+Thread_Producer_TextArea.getText());
Thread_Consumer_TextArea.setText(Consumer_print+"\n"+Thread_Consumer_TextArea.getText());
Thread_cache_TextArea.setText(Cache_print+"\n"+Thread_cache_TextArea.getText());
if(is_begin ==1 && is_end == 0 && is_start == 0) {
is_start = 1;
for (int i = 0; i < producerCount; i++) {
new Thread(p).start();
}
for (int i = 0; i < consumerCount; i++) {
new Thread(c).start();
}
}
if (is_begin ==1 && is_end == 0 && is_start ==1){
sleep_millis = 0;
Thread.sleep(sleep_millis);
}
if(is_begin == 0 && is_end ==1){
sleep_millis = 1000;
Thread.sleep(sleep_millis);
}
Thread.currentThread().sleep(1000);
}
}
}
Producer.java 、 Consumer.java 、 Cache.java 、 Main.java 共四部分实现生产者消费者问题
Producer.java 、 Consumer.java 、 Cache.java 三部分实现生产者消费者线程问题
Main.java 部分为验证执行和界面制作
实现功能:
下拉选择框选择缓冲区容量、生产者、消费者数量以及速度进行模拟
(进程与界面展示不同步)
由于作者比较憨批所以界面什么的都堆在一起了 不要介意……而且程序可能有bug 体谅一下 主要是学多线程 界面什么的 就不要太在意啦……
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)