生产者消费者java算法解释_关于java中生产者消费者模式的理解

在说生产者消费者模式之前,我觉得有必要理解一下 Obj.wait(),与Obj.notify()方法。wait()方法是指在持有对象锁的线程调用此方法时,会释放对象锁,同时休眠本线程。notify()方法是持有相同的对象锁来唤醒休眠的线程,使其具有抢占cpu的资格。可以理解同步方法,同步方法的对象锁就是谁调用这个方法,这个对象就是对象锁。

根据李兴华老师的视频讲解,建立一个生产者类,一个消费者类,还有一个Info类,贴上代码:

1.生产者类

packagecom.company;/*** Created by Administrator on 2016/8/30.*/

public class Productor implementsRunnable {privateInfo info;publicProductor(Info info) {this.info =info;

}

@Overridepublic voidrun() {for (int i=0;i<50;i++)

{if (i%2==0)

{//info.setTitle("陶帅");//info.setContent("一个帅哥");//try {//Thread.sleep(100);//} catch (InterruptedException e) {//e.printStackTrace();//}

info.set("陶帅","一个帅哥");

}else{//info.setTitle("可爱的动物");//info.setContent("草泥马");

info.set("可爱的动物","草泥马");//try {//Thread.sleep(100);//} catch (InterruptedException e) {//e.printStackTrace();//}

}

}

}

}

2.消费者类

packagecom.company;/*** Created by Administrator on 2016/8/30.*/

public class Consumer implementsRunnable {privateInfo info;publicConsumer(Info info) {this.info =info;

}

@Overridepublic voidrun() {for (int i=0;i<50;i++)

{try{

Thread.sleep(100);

}catch(InterruptedException e) {

e.printStackTrace();

}

info.get();

}

}

}

3.Info类(重点)

packagecom.company;/*** Created by Administrator on 2016/8/30.*/

public classInfo {privateString Title;privateString content;private boolean flag=true;//true表示可以生产不能取走消费,false相反

public synchronized voidset(String Titile,String content){if (!flag)

{try{

wait();

}catch(InterruptedException e) {

e.printStackTrace();

}

}this.Title=Titile;this.content=content;try{

Thread.sleep(100);

}catch(InterruptedException e) {

e.printStackTrace();

}

flag=false;

notify();

}public synchronized voidget(){if(flag)

{try{

wait();

}catch(InterruptedException e) {

e.printStackTrace();

}

}try{

Thread.sleep(100);

}catch(InterruptedException e) {

e.printStackTrace();

}

System.out.println(this.Title+"------->"+this.content);

flag=true;

notify();

}//public String getTitle() {//return Title;//}//

//public void setTitle(String title) {//Title = title;//}//

//public String getContent() {//return content;//}//

//public void setContent(String content) {//this.content = content;//}

}

4.测试类

packagecom.company;public classMain {public static voidmain(String[] args) {

Info info=newInfo();

Productor p=newProductor(info);

Consumer c=newConsumer(info);newThread(p).start();newThread(c).start();

}

}

总结分析:生产者和消费者两个线程同时抢占CPU,假如消费者先抢到,此时调用get()方法即消费取走,但是此时flag为true,因此会进入wait()方法,所以此时只能是生产者抢占到CPU,根据生产者调用set()方法,生产后执行

flag=false;

notify();

此时生产者和消费者所在的两个线程又站在同一起跑线上了,继续CPU争夺战。如果不幸的消费者又没有抢过生产者,生产者继续执行set();此时flag已经是false了,根据代码

if (!flag)

{try{

wait();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

所以生产者只能乖乖的wait();CPU回到消费者这里,循环往复,模式就出来了,完美!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
生产者消费者问题算法实现》 设计思想 因为有多个缓冲区,所以生产者线程没有必要在生成新的数据之前等待最后一个数据被消费者线程处理完毕。同样,消费者线程并不一定每次只能处理一个数据。在多缓冲区机制下,线程之间不必互相等待形成死锁,因而提高了效率。   多个缓冲区就好像使用一条传送带替代托架,传送带上一次可以放多个产品。生产者在缓冲区尾加入数据,而消费者则在缓冲区头读取数据。当缓冲区满的时候,缓冲区就上锁并等待消费者线程读取数据;每一个生产或消费动作使得传送带向前移动一个单位,因而,消费者线程读取数据的顺序和数据产生顺序是相同的。 可以引入一个count计数器来表示已经被使用的缓冲区数量。用hNotEmptyEvent 和hNotFullEvent 来同步生产者消费者线程。每当生产者线程发现缓冲区满( count=BufferSize ),它就等待hNotEmptyEvent 事件。同样,当消费者线程发现缓冲区空,它就开始等待hNotEmptyEvent。生产者线程写入一个新的数据之后,就立刻发出hNotEmptyEvent 来唤醒正在等待的消费者线程;消费者线程在读取一个数据之后,就发出hNotFullEvent 来唤醒正在等待的生产者线程。 程序的设计思想大致为:设置一while循环,pi生产者访问临界区,得到权限访问缓冲区,如果缓冲区满的,则等待,直到缓冲区非满;访问互斥锁,当得到互斥锁且缓冲区非满时,跳出while循环,开始产生新数据,并把数据存放于Buffer缓冲区,当数据存放结束则结束临界区;接着唤醒消费者线程;ci消费者访问临界区,得到权限访问缓冲区,如果缓冲区为空,没有可以处理的数据,则释放互斥锁且等待,直到缓冲区非空;当等到缓冲区非空时,跳出while循环;消费者获得数据,并根据所获得的数据按类别消费(当消费者获得的数据为大写字母时,则把大写字母转换成小写字母,并显示;当消费者获得的数据为小写字母时,则把小写字母转换成大写字母,并显示;当消费者获得的数据为字符0、1、2、……8、9时,把这些字符直接显示到屏幕;当消费者获得的数据为符号(+、-、*、\……)时,把这些符号打印成7行7列的菱形);处理完数据后,结束临界区;接着唤醒生产者线程。
以下是一个基于Java和Swing的生产者消费者模型时间片轮转算法的窗口实现完整代码: ``` import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.LinkedList; import java.util.Queue; import java.util.Random; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.Timer; public class ProducerConsumer extends JFrame implements ActionListener { private static final long serialVersionUID = 1L; private static final int WIDTH = 600; private static final int HEIGHT = 400; private static final int BUFFER_SIZE = 10; private static final int PRODUCER_DELAY = 1000; private static final int CONSUMER_DELAY = 2000; private static final int TIME_QUANTUM = 100; private static final int MAX_PRODUCE = 3; private static final int MAX_CONSUME = 2; private static final int PRODUCE_BUTTON_INDEX = 0; private static final int CONSUME_BUTTON_INDEX = 1; private static final String PRODUCE_BUTTON_TEXT = "Start Producer"; private static final String CONSUME_BUTTON_TEXT = "Start Consumer"; private static final String PRODUCE_STATUS_TEXT = "Producer Status: %s"; private static final String CONSUME_STATUS_TEXT = "Consumer Status: %s"; private static final String BUFFER_STATUS_TEXT = "Buffer Status: %d/%d"; private static final String LOG_FORMAT = "[%s] %s %d\n"; private static final String EMPTY_BUFFER_INDICATOR = "-"; private final Object lock = new Object(); private final Random random = new Random(); private final Queue<Integer> buffer = new LinkedList<>(); private final Timer producerTimer = new Timer(PRODUCER_DELAY, this); private final Timer consumerTimer = new Timer(CONSUMER_DELAY, this); private final JTextArea logArea = new JTextArea(); private final JLabel produceStatusLabel = new JLabel(String.format(PRODUCE_STATUS_TEXT, "Stopped")); private final JLabel consumeStatusLabel = new JLabel(String.format(CONSUME_STATUS_TEXT, "Stopped")); private final JLabel bufferStatusLabel = new JLabel(String.format(BUFFER_STATUS_TEXT, 0, BUFFER_SIZE)); private final JButton[] buttons = { new JButton(PRODUCE_BUTTON_TEXT), new JButton(CONSUME_BUTTON_TEXT) }; private boolean producerRunning = false; private boolean consumerRunning = false; private int timeLeft = TIME_QUANTUM; public ProducerConsumer() { super("Producer Consumer Simulation"); setPreferredSize(new Dimension(WIDTH, HEIGHT)); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLayout(new BorderLayout()); JPanel controlPanel = new JPanel(new FlowLayout()); for (JButton button : buttons) { button.addActionListener(this); controlPanel.add(button); } JPanel statusPanel = new JPanel(new FlowLayout()); statusPanel.add(produceStatusLabel); statusPanel.add(consumeStatusLabel); statusPanel.add(bufferStatusLabel); JPanel logPanel = new JPanel(new BorderLayout()); logPanel.add(new JLabel("Log:"), BorderLayout.NORTH); logPanel.add(logArea, BorderLayout.CENTER); add(controlPanel, BorderLayout.NORTH); add(statusPanel, BorderLayout.CENTER); add(logPanel, BorderLayout.SOUTH); pack(); setLocationRelativeTo(null); setVisible(true); } private void produce() { int count = random.nextInt(MAX_PRODUCE) + 1; synchronized (lock) { while (buffer.size() + count > BUFFER_SIZE) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < count; i++) { buffer.add(random.nextInt(100)); } bufferStatusLabel.setText(String.format(BUFFER_STATUS_TEXT, buffer.size(), BUFFER_SIZE)); logArea.append(String.format(LOG_FORMAT, "PRODUCE", "Produced", count)); lock.notifyAll(); } } private void consume() { int count = random.nextInt(MAX_CONSUME) + 1; synchronized (lock) { while (buffer.size() < count) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < count; i++) { buffer.poll(); } bufferStatusLabel.setText(String.format(BUFFER_STATUS_TEXT, buffer.size(), BUFFER_SIZE)); logArea.append(String.format(LOG_FORMAT, "CONSUME", "Consumed", count)); lock.notifyAll(); } } private void runProducer() { producerRunning = true; produceStatusLabel.setText(String.format(PRODUCE_STATUS_TEXT, "Running")); producerTimer.start(); } private void runConsumer() { consumerRunning = true; consumeStatusLabel.setText(String.format(CONSUME_STATUS_TEXT, "Running")); consumerTimer.start(); } private void stopProducer() { producerRunning = false; produceStatusLabel.setText(String.format(PRODUCE_STATUS_TEXT, "Stopped")); producerTimer.stop(); } private void stopConsumer() { consumerRunning = false; consumeStatusLabel.setText(String.format(CONSUME_STATUS_TEXT, "Stopped")); consumerTimer.stop(); } private void logEmptyBuffer() { logArea.append(String.format(LOG_FORMAT, "CONSUME", "Buffer is empty", 0)); } private void runTimeSlice() { timeLeft -= TIME_QUANTUM; if (timeLeft <= 0) { timeLeft = TIME_QUANTUM; synchronized (lock) { lock.notifyAll(); } } } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == buttons[PRODUCE_BUTTON_INDEX]) { if (producerRunning) { stopProducer(); } else { runProducer(); } } else if (e.getSource() == buttons[CONSUME_BUTTON_INDEX]) { if (consumerRunning) { stopConsumer(); } else { runConsumer(); } } else if (e.getSource() == producerTimer) { produce(); } else if (e.getSource() == consumerTimer) { synchronized (lock) { if (buffer.isEmpty()) { logEmptyBuffer(); lock.notifyAll(); } else { consume(); } } } runTimeSlice(); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new ProducerConsumer(); } }); } } ``` 在这个实现,我们使用了两个Timer对象来模拟生产者消费者的生产和消费行为。每当Timer对象触发ActionEvent时,我们会调用相应的生产或消费方法。 对于生产方法,我们随机生成一定数量的数字,并把它们添加到缓冲区。如果缓冲区已满,我们会等待直到有足够的空间来添加新的数字。当生产完成后,我们会更新缓冲区状态并记录日志,然后唤醒任何等待的线程。 对于消费方法,我们随机生成一定数量的数字,并从缓冲区移除它们。如果缓冲区为空,我们会记录日志并唤醒任何等待的线程。当消费完成后,我们会更新缓冲区状态并记录日志,然后唤醒任何等待的线程。 我们还实现了时间片轮转算法,并在每个时间片结束时唤醒任何等待的线程。这是为了确保在生产者消费者之间公平地分配CPU时间。 最后,我们使用Swing创建了一个简单的GUI界面,使用户能够启动和停止生产者消费者。我们还在界面上显示了生产者消费者的状态以及缓冲区的状态和日志。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值