多线程程序一段问题代码分析(生产者消费者)_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 多线程程序一段问题代码分析(生产者消费者)

多线程程序一段问题代码分析(生产者消费者)

 2013/7/10 3:35:36  jinnianshilongnian  程序员俱乐部  我要评论(0)
  • 摘要:问题在《一个java生产者消费者代码的问题》,解答一下,只解释原因,其他不考虑。作者要的是一个生产者生成,接着必须有一个消费者消费,那这不是需要单线程吗?或者使用1个大小的阻塞队列。所以只谈论问题本身,不谈论好不好。具体代码:importjava.util.concurrent.locks.Condition;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock
  • 标签:程序 多线程 问题 代码 分析 消费者 线程

问题在《一个java生产者消费者代码的问题》,解答一下,只解释原因,其他不考虑。

?

作者要的是一个生产者生成,接着必须有一个消费者消费,那这不是需要单线程吗?或者使用1个大小的阻塞队列。所以只谈论问题本身,不谈论好不好。

?

具体代码:

class="java" name="code">import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;


//生产/消费者模式

public class Basket {

    Lock lock = new ReentrantLock();


    // 产生Condition对象

    Condition produced = lock.newCondition();

    Condition consumed = lock.newCondition();

    boolean available = false;


    public void produce() throws InterruptedException {

        lock.lock();


        try {

            if (available) {

                produced.await(); // 放弃lock进入睡眠

            }


            System.out.println("Apple produced.");


            available = true;


            consumed.signal(); // 发信号唤醒等待这个Condition的线程

        } finally {

            lock.unlock();

        }

    }


    public void consume() throws InterruptedException {

        lock.lock();


        try {

            if (!available) {

                consumed.await(); // 放弃lock进入睡眠

            }


            /* 吃苹果 */

            System.out.println("Apple consumed.");


            available = false;


            produced.signal(); // 发信号唤醒等待这个Condition的线程

        } finally {

            lock.unlock();

        }

    }

}

?

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

//测试用类
public class ConditionTester {

    public static void main(String[] args) throws InterruptedException {
        final Basket basket = new Basket();

        // 定义一个producer
        Runnable producer = new Runnable() {
            public void run() {
                try {
                    basket.produce();
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        };

        // 定义一个consumer
        Runnable consumer = new Runnable() {
            public void run() {
                try {
                    basket.consume();
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        };

        // 各产生10个consumer和producer
        ExecutorService service = Executors.newCachedThreadPool();

        for (int i = 0; i < 4; i++)
            service.submit(consumer);

        Thread.sleep(2000 * 2);

        for (int i = 0; i < 4; i++)
            service.submit(producer);

        service.shutdown();
    }
}

?

原因分析:

1、假设前面有2个producer(此时available=true)

1.1、一个在等待lock

1.2、一个await

2、consumer生成内容后,available=false,produced.signal(); 最后lock.unlock();

3.1、因为lock.unlock所以会触发一个lock获取到锁(虽然signal也会触发等待这个条件的其他线程,但是多线程大家都知道什么时候触发这是不确定的),如果此时正好是[1.1]那么因为available=false,执行完释放锁

3.2、produced.signal()所以会触发一个await的producer;

?

解决方案:

只要保证[3.1]还是需要await即可解决问题

?

所以加一个 AtomicInteger producedAwaitCounter = new AtomicInteger(0); 统计当前等待的生产者,如果当前available=false,但已经有生产者生成了内容,那么先等待消费者消费了再说

?

? ? ? ? ? ? if (available || producedAwaitCounter.get() > 0) {

? ? ? ? ? ? ? ? producedAwaitCounter.incrementAndGet();

? ? ? ? ? ? ? ? produced.await(); // 放弃lock进入睡眠

? ? ? ? ? ? ? ? producedAwaitCounter.decrementAndGet();

? ? ? ? ? ? }

?

当然最简单的是使用:自旋,原理可以自己分析下:

? ? ? ? ? ? while (available) {

? ? ? ? ? ? ? ? produced.await(); // 放弃lock进入睡眠

? ? ? ? ? ? }

?

?

package com.sishuok.es.test;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;


//生产/消费者模式

public class Basket {

    Lock lock = new ReentrantLock(true);


// 产生Condition对象

    Condition produced = lock.newCondition();

    Condition consumed = lock.newCondition();

    boolean available = false;
    AtomicInteger producedAwaitCounter = new AtomicInteger(0);


    public void produce() throws InterruptedException {

        lock.lock();

        try {

            if (available || producedAwaitCounter.get() > 0) {
                producedAwaitCounter.incrementAndGet();
                produced.await(); // 放弃lock进入睡眠
                producedAwaitCounter.decrementAndGet();
            }

            System.out.println("Apple produced.");


            available = true;


            consumed.signal(); // 发信号唤醒等待这个Condition的线程

        } finally {
            lock.unlock();
        }

    }


    public void consume() throws InterruptedException {

        lock.lock();


        try {

            if (!available) {
                consumed.await(); // 放弃lock进入睡眠
            }

            /* 吃苹果 */

            System.out.println("Apple consumed.");


            available = false;

            produced.signal(); // 发信号唤醒等待这个Condition的线程
        } finally {
            lock.unlock();
        }

    }

}

?

在回答里还一个类似的,不过还是不太一样。

http://blog.csdn.net/liguogangde/article/details/9103501

?

发表评论
用户名: 匿名