Java多线程之生产者消费者问题<三>:使用阻塞队列更优雅地解决生产者消费者问题

前一篇文章讲了如何使用java5中的重入锁和条件变量优雅地解决生产者消费者问题,本文将继续探究java并发包(concurrent),寻求更好的解决方案。

java并发包中提供了阻塞队列(BlockingQueue),查看该类的注释说明,大概翻译下:这是一个额外支持等待队列非空或等待队列可用的队列,意思就是当线程去队列取元素时,如果没有元素线程将等待,直到有可用的有元素可取;当向队列中添加元素时,判断队列是否已满,如果已满,则线程等待,直到队列可以添加元素。这样一看,阻塞队列完全可以解决生产者消费者问题。代码如下:

Consumer.java

package CreatorAndConsumerBlock;

public class Consumer implements Runnable {
    /**
     * 线程资源
     */
    private Plate plate;

    public Consumer(Plate plate) {
        this.plate = plate;
    }

    @Override
    public void run() {
        plate.getEgg();
    }
}
Creator.java
package CreatorAndConsumerBlock;

/**
 * 生产者
 *
 * @author Martin
 */
public class Creator implements Runnable {
    /**
     * 线程资源
     */
    private Plate plate;

    public Creator(Plate plate) {
        this.plate = plate;
    }

    @Override
    public void run() {
        Object egg = new Object();
        plate.addEgg(egg);
    }
}
Plate.java
package CreatorAndConsumerBlock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 盘子,表示共享的资源
 *
 * @author Martin
 */
public class Plate {
    /**
     * 将arraylist换成阻塞队列,可见使用了阻塞队列后,代码中再也没有了lock、condition等了,完全不需要手动控制线程的等待还是唤醒了
     */
    private ArrayBlockingQueue<Object> eggs = new ArrayBlockingQueue<Object>(99999);

    /**
     * 获取蛋
     *
     * @return
     */
    public Object getEgg() {
        try {
            Object egg = eggs.take();
            System.out.println("消费者取蛋,当前剩余:" + eggs.size());
            return egg;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return null;
    }


    /**
     * 加入蛋
     *
     * @return
     */
    public void addEgg(Object egg) {
        try {
            eggs.put(new Object());
            System.out.println("生产者生蛋,当前剩余:" + eggs.size());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
Tester.java
package CreatorAndConsumerBlock;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Tester {
    public static void main(String[] args)
    {
        //共享资源
        Plate plate = new Plate();
        ExecutorService pool = Executors.newFixedThreadPool(100);

        //添加生产者和消费者
        for(int i = 0 ; i < 100000; i ++)
        {
            pool.execute(new Creator(plate));
            pool.execute(new Consumer(plate));
        }

        pool.shutdown();
    }
}
和使用synchronized关键字和重入锁、条件变量相比,代码大大简化,程序中完全不需要关系线程如何同步资源,什么时候唤醒其他线程。其实,我们查看阻塞队列的源码,其实其也是使用重入锁、条件变量来实现的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值