Android 价值千万的java多线程<三>生产者消费者模型四种实现方法

 

1).Android 价值千万   java线程专题:Wait&notify&join&Yield

http://blog.csdn.net/whb20081815/article/details/65627387

2).Android 价值千万    java多线程同步 <二>Callable和Future&FutureTask

http://blog.csdn.net/whb20081815/article/details/65630694

3).Android 价值千万    java多线程<三>生产者消费者模型四种实现方法

http://blog.csdn.net/whb20081815/article/details/65635647

 4).

Android 价值千万    java多线程同步 <四> synchronized&Lock&Atomic6种方式

 

http://blog.csdn.net/whb20081815/article/details/66971983

5).Android 价值千万java多线程同步 <五>CountDownLatch(计数器)和Semaphore(信号量)

http://blog.csdn.net/whb20081815/article/details/68498371

 

 

生产者消费者模型

 

同步问题核心在于:如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。Java语言在多线程编程上实现了完全对象化,提供了对同步机制的良好支持。在Java中一共有四种方法支持同步,其中前三个是同步方法,一个是管道方法。

(1)wait() / notify()方法

(2)BlockingQueue阻塞队列方法

(3)await() / signal()方法

(4)PipedInputStream / PipedOutputStream

 

先只介绍常用的2中

 

实际上,准确说应该是生产者-消费者-仓储模型,离开了仓储,生产者消费者模型就显得没有说服力了。

对于此模型,应该明确一下几点:

1、生产者仅仅在仓储未满时候生产,仓满则停止生产。

2、消费者仅仅在仓储有产品时候才能消费,仓空则等待。

3、当消费者发现仓储没产品可消费时候会通知生产者生产。

4、生产者在生产出可消费产品时候,应该通知等待的消费者去消费。

 

一、wait() / notify()方法

wait() / nofity()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。

wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。

notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。

 

 

 

/**
 * 仓库类Storage实现缓冲区
 *
 *
 */
public class StorageNotify
        extends Strorage{
    // 仓库最大存储量
    private final int MAX_SIZE = 100;

    // 仓库存储的载体
    private LinkedList<Object> list = new LinkedList<Object>();

    // 生产num个产品
    public void produce(int num)
    {
        // 同步代码段
        synchronized (list)
        {
            // 如果仓库剩余容量不足,如果list.size() + num>MAX_SIZE问题就来了
            while (list.size() + num > MAX_SIZE)
            {
                System.out.println("【要生产的产品数量】:" + num + "/t【库存量】:"
                        + list.size() + "/t暂时不能执行生产任务!");
                try
                {
                    // 由于条件不满足,生产阻塞
                    list.wait();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }

            // 生产条件满足情况下,生产num个产品
            for (int i = 1; i <= num; ++i)
            {
                list.add(new Object());
            }

            System.out.println("【已经生产产品数】:" + num + "/t【现仓储量为】:" + list.size());

            list.notifyAll();
        }
    }

    // 消费num个产品
    public void consume(int num)
    {
        // 同步代码段
        synchronized (list)
        {
            // 如果仓库存储量不足
            while (list.size() < num)
            {
                System.out.println("【要消费的产品数量】:" + num + "/t【库存量】:"
                        + list.size() + "/t暂时不能执行消费任务!");
                try
                {
                    // 由于条件不满足,消费阻塞
                    list.wait();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }

            // 消费条件满足情况下,消费num个产品
            for (int i = 1; i <= num; ++i)
            {
                list.remove();
            }

            System.out.println("【已经消费产品数】:" + num + "/t【现仓储量为】:" + list.size());
            list.notifyAll();

        }
    }
public void testProduct(int type){
    // 仓库对象
    Strorage storage ;
    if(type==BlockingQueueType){
        storage = new StorageBlockingQueue();
    }else{
        storage = new StorageNotify();
    }

    // 生产者对象
    Producer p1 = new Producer(storage);
    Producer p2 = new Producer(storage);
    Producer p3 = new Producer(storage);
    Producer p4 = new Producer(storage);
    Producer p5 = new Producer(storage);
    Producer p6 = new Producer(storage);
    Producer p7 = new Producer(storage);

    // 消费者对象
    Consumer c1 = new Consumer(storage);
    Consumer c2 = new Consumer(storage);
    Consumer c3 = new Consumer(storage);

    // 设置生产者产品生产数量
    p1.setNum(10);
    p2.setNum(10);
    p3.setNum(10);
    p4.setNum(10);
    p5.setNum(10);
    p6.setNum(10);
    p7.setNum(80);

    // 设置消费者产品消费数量
    c1.setNum(50);
    c2.setNum(20);
    c3.setNum(30);

    // 线程开始执行
    c1.start();
    c2.start();
    c3.start();
    p1.start();
    p2.start();
    p3.start();
    p4.start();
    p5.start();
    p6.start();
    p7.start();
}

 

二、BlockingQueue阻塞队列方法

 

BlockingQueue是JDK5.0的新增内容,它是一个已经在内部实现了同步的队列,它可以在生成对象时指定容量大小。它用于阻塞操作的是put()和take()方法。

put()方法:类似于我们上面的生产者线程,容量达到最大时,自动阻塞。

take()方法:类似于我们上面的消费者线程,容量为0时,自动阻塞。

/**
 * Created by Administrator on 2017/3/24.
 * 采用阻塞队列的形式
 */
public class StorageBlockingQueue extends Strorage{


    // 仓库最大存储量
    private final int MAX_SIZE = 100;

    // 仓库存储的载体
    private LinkedBlockingQueue<Object> list = new LinkedBlockingQueue<Object>(
            100);

    // 生产num个产品
    public void produce(int num)
    {
        // 如果仓库剩余容量为0
        if (list.size() == MAX_SIZE)
        {
            System.out.println("【库存量】:" + MAX_SIZE + "/t暂时不能执行生产任务!");
        }

        // 生产条件满足情况下,生产num个产品
        for (int i = 1; i <= num; ++i)
        {
            try
            {
                // 放入产品,自动阻塞
                list.put(new Object());
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }

            System.out.println("【现仓储量为】:" + list.size());
        }
    }

    // 消费num个产品
    public void consume(int num)
    {
        // 如果仓库存储量不足
        if (list.size() == 0)
        {
            System.out.println("【库存量】:0/t暂时不能执行消费任务!");
        }

        // 消费条件满足情况下,消费num个产品
        for (int i = 1; i <= num; ++i)
        {
            try
            {
                // 消费产品,自动阻塞
                list.take();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }

        System.out.println("【现仓储量为】:" + list.size());
    }

 

结果:

 

【要消费的产品数量】:50/t【库存量】:0/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11086/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:20/t【库存量】:0/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11030/threadbase.peng.cx.com.threadproducecomsume D/Activity: performCreate Call secproduct feature valuefalse
03-24 18:57:18.509 11030-11088/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:10
03-24 18:57:18.509 11030-11030/threadbase.peng.cx.com.threadproducecomsume D/Activity: performCreate Call debug elastic valuetrue
03-24 18:57:18.509 11030-11087/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:30/t【库存量】:10/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:50/t【库存量】:10/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11089/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:20
03-24 18:57:18.509 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:50/t【库存量】:20/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11087/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:30/t【库存量】:20/t暂时不能执行生产任务!
03-24 18:57:18.509 11030-11091/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:30
03-24 18:57:18.519 11030-11090/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:40
03-24 18:57:18.519 11030-11092/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:50
03-24 18:57:18.519 11030-11086/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经消费产品数】:20/t【现仓储量为】:30
03-24 18:57:18.519 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:50/t【库存量】:30/t暂时不能执行生产任务!
03-24 18:57:18.519 11030-11087/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经消费产品数】:30/t【现仓储量为】:0
03-24 18:57:18.519 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:50/t【库存量】:0/t暂时不能执行生产任务!
03-24 18:57:18.519 11030-11093/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:10/t【现仓储量为】:10
03-24 18:57:18.519 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【要消费的产品数量】:50/t【库存量】:10/t暂时不能执行生产任务!
03-24 18:57:18.519 11030-11094/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经生产产品数】:80/t【现仓储量为】:90
03-24 18:57:18.519 11030-11085/threadbase.peng.cx.com.threadproducecomsume I/System.out: 【已经消费产品数】:50/t【现仓储量为】:40

LinkedBlockingQueue:在代码里的用例之一:线程池 ExecutorService:

只要设置最大的值就可以了,其他自动处理

 

mThreadPool = Executors.newFixedThreadPool(3);

 

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

 

AS源代码地址:不知道为什么上传不了

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值