多线程(2)——生产者与消费者模式

为什么要有生产者与消费者模式

  • 为了解决生产者和消费者速度不匹配的问题,如果生产者的速度大于消费者的速度,则生产者要等待消费者处理完生产者才能产生新的数据。

生产者与消费者模式有两种

  • 单生产者与单消费者
  • 多生产者与多消费者

实现生产者与消费者模式有二种实现方式

  • wait和notify方式
  • ReentrantLock的condition方式

代码示例

  • 示例实现的是多生产者与多消费者模式,采用的是ReentrantLock的condition方式
  • 特殊情况:按照上述一生产与一消费的情况,通过创建多个生产者和消费者线程,实现多生产与多消费的情况,将会出现“假死”。
  • 具体原因:多个生产者和消费者线程。当全部运行后,生产者线程生产数据后,可能唤醒的同类即生产者线程。此时可能会出现如下情况:所有生产者线程进入等待状态,然后消费者线程消费完数据后,再次唤醒的还是消费者线程,直至所有消费者线程都进入等待状态,此时将进入“假死”。
  • 解决方法:将notify()或signal()方法改为notifyAll()或signalAll()方法,这样就不怕因为唤醒同类而进入“假死”状态了。
/**
 * 生产者
 *
 * @author jiangxinlin
 * @version 2018-06-12
 */
public class Producer {
    // 锁
    private Lock lock;

    // Condition的作用是对锁进行更精确的控制
    private Condition condition;

    public Producer(Lock lock, Condition condition) {
        this.lock = lock;
        this.condition = condition;
    }

    public void setValue() {
        try {
            /*
                - 如果该锁定没有被另一个线程保持,则获取该锁定并立即返回,将锁定的保持计数设置为 1。
                - 如果当前线程已经保持该锁定,则将保持计数加 1,并且该方法立即返回。
                - 如果该锁定被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁定之前,
                该线程将一直处于休眠状态,此时锁定保持计数被设置为 1。
             */
            lock.lock();
            System.out.println(Thread.currentThread().getId() + "》》》进入生产者");

            // list大小超过10,不生产
            while (StringObject.list != null && StringObject.list.size() >= 10) {
                // 当前线程在接到信号或被中断之前一直处于等待状态
                condition.await();
            }

            String value = System.currentTimeMillis() + "" + System.nanoTime();
            System.out.println(Thread.currentThread().getId() + "---生产的值是:" + value);
            StringObject.list.add(value);
            // 唤醒在此Lock对象上等待的所有线程
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 把解锁操作括在finally字句之内是至关重要的,如果受保护的代码抛出异常,
            // 锁可以得到释放,这样可以避免死锁的发生
            lock.unlock();
        }
    }
}

/**
 * 消费者
 *
 * @author jiangxinlin
 * @version 2018-06-12
 */
public class Consumer {
    private Lock lock;
    private Condition condition;

    public Consumer(Lock lock, Condition condition) {
        super();
        this.lock = lock;
        this.condition = condition;
    }

    public void getValue() {
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getId() + "》》》进入消费者");
            while (StringObject.list != null && StringObject.list.size() == 0) {
                //没值,不进行消费
                condition.await();
            }
            String value = StringObject.list.get(StringObject.list.size() - 1);
            System.out.println(Thread.currentThread().getId() + "---消费的值是:" + value);
            StringObject.list.remove(value);
            condition.signalAll();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Lock lock = new ReentrantLock();
        Condition newCondition = lock.newCondition();
        Producer product = new Producer(lock, newCondition);
        Consumer consumer = new Consumer(lock, newCondition);
        for (int i = 0; i < 3; i++) {
            ThreadProducer pThread = new ThreadProducer(product);
            ThreadConsumer cThread = new ThreadConsumer(consumer);
            pThread.start();
            cThread.start();
        }

    }

}

/**
 * 生产者线程
 * @author jiangxinlin
 * @version 2018-06-12
 */
public class ThreadProducer extends Thread {
    private Producer producer;

    public ThreadProducer(Producer producer) {
        this.producer = producer;
    }

    @Override
    public void run() {
        //死循环,不断的生产
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            producer.setValue();
        }
    }
}

/**
 * 消费者线程
 * @author jiangxinlin
 * @version 2018-06-12
 */
public class ThreadConsumer extends Thread {
    private Consumer consumer;

    public ThreadConsumer(Consumer consumer) {
        this.consumer = consumer;
    }

    @Override
    public void run() {
        //死循环,不断的消费
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            consumer.getValue();
        }
    }

}

/**
 * 生产者与消费者操作的公共变量
 * @author jiangxinlin
 * @version 2018-06-12
 */
public class StringObject {
    public static List<String> list = new ArrayList<>();
}

猜你喜欢

转载自blog.csdn.net/jiang13479/article/details/80676196