17. 线程通信-Condition

java 多线程系列文章列表, 请查看目录: 《java 多线程学习笔记》

1. 线程通信-Condition

  • 当使用synchronized 进行线程同步时, 可以使用Object的wait(), notify(), notifyAll() 方法进行线程通信.
  • 但是当使用Lock 对象保证线程同步时, 便不能使用Object 的方法来进行线程通信了, 而是通过Condition 对象进行线程通信

1.1 Condition API

Condition 提供了和Object 通信方法类似的API, 还做了一定的增强.

  • awaite():
    • 类似于Object的wait()方法, 使当前线程等待. 直达其它线程调用该condition对象的signal()或signalAll()方式时被唤醒.
    • condition 还提供了一些增强方法, awaitNanos(long nanosTimeout), awaitUntil(Date), awaituninterruptibly()
  • signal(): 唤醒使用该condition对象进入阻塞状态的任意一个线程.
  • signalAll(): 唤醒使用该condition 对象进入阻塞状态的所有线程

2. Condition 示例

我们依然借助于签名的示例进行改造, 只是不在使用synchronized 进行加锁, 而是通过Lock 对象进行加锁.

2.1 使用Lock 改造的Product

  • Conditon 是通过Lock 对象new出来的.
  • 一定要注意释放锁, 放在最外层的finally 代码块儿中
  • 一个lock 对象可以创建多个condition 对象, 由哪个Condition对象进入的阻塞状态, 只能被哪个Condition唤醒.
public class Product {

    private int number = 1;

    // 同步锁
    private Lock lock = new ReentrantLock();

    // 通信对象
    private Condition condition = lock.newCondition();

    public void sale(){

        // 加锁
        lock.lock();

        try {
            // 如果商品数量小于0 , 则线程等待
            while (number <= 0) {
                System.out.println("商品剩余为0, 等待补货!");
                this.condition.await();
            }

            System.out.println(Thread.currentThread().getName() + "-售出1件商品, 剩余商品:" + --number);

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 一定要记得释放锁
            lock.unlock();
        }
    }

    public void purchase() {

        // 加锁
        lock.lock();

        try {

            System.out.println(Thread.currentThread().getName() + "-进货1件商品, 剩余商品:" + ++number);

            // 通知所有的等待线程, 可能会产生虚假唤醒
            this.condition.signalAll();

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 一定要记得释放锁
            lock.unlock();
        }
    }

}

2.2 测试用例

public static void main(String[] args) {

    Product product = new Product();

    // 启动三个线程消费
    for (int i = 0; i < 3; i++) {
        new Thread("消费者" + i){
            @Override
            public void run() {
                while (true) {
                    product.sale();
                    ThreadUtil.sleep(5);
                }
            }
        }.start();
    }

    // 启动一个线程生产
    new Thread("生产者"){
        @Override
        public void run() {
            while (true) {
                product.purchase();
                ThreadUtil.sleep(10);
            }
        }
    }.start();

    ThreadUtil.sleep(10000);
}

2.3 测试输出

消费者1-售出1件商品, 剩余商品:0
商品剩余为0, 等待补货!
生产者-进货1件商品, 剩余商品:1
消费者2-售出1件商品, 剩余商品:0
商品剩余为0, 等待补货!
商品剩余为0, 等待补货!
商品剩余为0, 等待补货!
生产者-进货1件商品, 剩余商品:1
消费者0-售出1件商品, 剩余商品:0
发布了321 篇原创文章 · 获赞 676 · 访问量 147万+

猜你喜欢

转载自blog.csdn.net/zongf0504/article/details/100186196
今日推荐