引言:生产者消费者问题是一个十分经典的多线程问题。为了更加形象地描述这个问题,采用可视化的形式展示此过程。
生产者消费者问题也称有限缓冲问题。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
当我们在思考如何解决这个问题的时候一定要联系实际。实际生活中(不考虑直接点对点模式),工厂生产的商品一般会通过经销商销售,消费者从经销商中购买商品。经销商手中的存货是有限的,同时他需要的商品也是有限的。当他不需要商品的时候,生产商不能再生产更多商品;当他没有存货的时候,消费者无法从他手中购买。这里,经销商就相当于一个缓冲区。
这种生产者-消费者模式有什么好处呢?使用这种模式,可以让消费者、生产者互相独立,生产者不需要依赖消费者的消费速度,它只关心缓冲区的状况。
多线程并发存在着线程安全问题,主要在于存在共享数据以及多个线程共同操作共享数据。使用synchronized可以保证线程互斥的访问代码。其原理在于它可以保证方法或者代码块在同一时刻只有一个可以进入到临界区,还可以保证共享变量的内存可见性
synchronized一般称"同步锁",在修饰代码块的时候需要传入一个对象作为"锁"的对象。线程同步就是利用锁机制先给共享资源上锁,只有拿到锁的线程才可以访问共享资源,其他线程进入等待状态
wait方法()是Object类的方法,其作用是使当前执行代码的线程进入等待。在调用wait()方法之前,线程必须获得该对象的锁,即只能在同步方法或同步块中调用wait()方法。wait()方法执行之后,当前线程释放锁。从wait()返回之前,线程会与其他线程产生资源竞争。当调用wait()时,如果没有锁将会抛出异常
notify()方法用来通知那些可能等待该对象的对象锁的其他线程,若有多个线程,则随机选择wait状态的线程对其notify,使它获得该对象的对象锁。但是,线程不会马上释放锁,而是等到执行notify()方法的线程将程序执行完后即退出synchronized语句块后,该线程才会释放锁。注意,操作不当可能会出现过早通知
notifyAll()使所有线程退出wait状态
总之,简单来讲:wait()使线程停止运行,notify()使线程继续运行
class Frame extends JFrame
{
public int width=1500;
public int height=1500;
UI ui=new UI();
public Container container;
public Frame()
{
setTitle("生产者消费者问题");
setSize(width,height);
setLocation(300,0);
container=getContentPane();
container.add(ui);
}
}
class UI extends JPanel
{
public static JProgressBar producerBar;//表示生产者生产进度
public static JLabel producerJLabel;//表示生产者生产个数
public static JLabel bufferJLabel;//缓冲区
public static JLabel amountJLabel;//缓冲区个数
public static JProgressBar consumerBar;//表示消费者消费速度
public static JLabel consumerJLabel;//表示消费者消费个数
JButton bt1;//生产者开始生产
JButton bt2;//生产者停止生产
JButton bt3;//消费者开始消费
JButton bt4;//消费者停止消费
public UI()
{
setLayout(null);
setSize(1400,1400);
producerBar=new JProgressBar();
consumerBar=new JProgressBar();
bt1=new JButton("开始生产");
bt2=new JButton("停止生产");
bt3=new JButton("开始消费");
bt4=new JButton("停止消费");
producerJLabel=new JLabel("生产者");
consumerJLabel=new JLabel("消费者");
bufferJLabel=new JLabel("缓冲区 (最大容量25)");
amountJLabel=new JLabel("商品数量:0");
producerBar.setBackground(Color.WHITE);
producerBar.setForeground(Color.BLACK);
consumerBar.setBackground(Color.WHITE);
producerBar.setForeground(Color.BLACK);
bt1.setBounds(50,170,70,60);
bt2.setBounds(150,170,70,60);
bt3.setBounds(950, 700, 70, 60);
bt4.setBounds(1050,700,70,60);
bufferJLabel.setBounds(550,350,200,200);
amountJLabel.setBounds(550,300,200,400);
producerJLabel.setBounds(50,70,50,50);
producerBar.setBounds(50, 120, 480, 40);
consumerJLabel.setBounds(950,600,50,50);
consumerBar.setBounds(950,650,480,40);
add(producerBar);
add(producerJLabel);
add(consumerBar);
add(consumerJLabel);
add(bt1);
add(bt2);
add(bt3);
add(bt4);
add(bufferJLabel);
add(amountJLabel);
}
}
class Buffer
{
private static final int max=25;//缓冲区最大容量
private LinkedList
class Producer implements Runnable
{
Buffer buffer;
JProgressBar produceBar;//生产进度条
int i;
public Producer(Buffer buffer,JProgressBar produceBar) {
// TODO Auto-generated constructor stub
this.buffer=buffer;
this.produceBar=produceBar;
}
@Override
public void run()
{
while(true)
{
try {
if(i<=25)
{
i++;
produceBar.setValue(i*4);
try {
Thread.sleep(200);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
buffer.produce();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable
{
Buffer buffer;
JProgressBar consumeBar;//消费进度条
int i;
public Consumer(Buffer buffer,JProgressBar consumeBar) {
// TODO Auto-generated constructor stub
this.buffer=buffer;
this.consumeBar=consumeBar;
}
@Override
public void run()
{
while(true)
{
try {
if(i<=25)
{
i++;
consumeBar.setValue(i*4);
try {
Thread.sleep(200);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
buffer.consume();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
Buffer buffer;//缓冲区
Producer producer;//生产者
Consumer consumer;//消费者
Thread thread1;//线程1用于控制生产行为的开始与暂停
Thread thread2;//线程2用于控制消费行为的开始与暂停
buffer=new Buffer(amountJLabel);
public UI()
{
bt1.addActionListener(new ActionListener() {//开始生产
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(thread1!=null)
{
try {
thread1.stop();
} catch (Exception e2) {
// TODO: handle exception
}
}
thread1=new Thread(new Producer(buffer,producerBar));
thread1.start();
}
});
bt2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(thread1!=null)
{
try {
thread1.stop();
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
}
});
bt3.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(thread2!=null)
{
try {
thread2.stop();
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
thread2=new Thread(new Consumer(buffer,consumerBar));
thread2.start();
}
});
bt4.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(thread2!=null)
{
try {
thread2.stop();
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
}
});
}