资讯专栏INFORMATION COLUMN

Java多线程基础(1)Condition

wangtdgoodluck / 1002人阅读

摘要:造成当前线程在接到信号被中断或到达指定最后期限之前一直处于等待状态。我们喜欢在多带带的等待中保存线程和线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。

Condition接口
Condition的功能类似于传统线程技术中的Object.wait()和Object.notify()方法的功能,但它是将这些方法分解成不同的对象,所以可以将这些对象与任意的Lock实现组合使用,实现在不同的条件下阻塞或唤醒线程;也就是说,这其中的Lock替代了synchronized方法和语句的使用,Condition替代了Object 监视器方法(wait、notify 和 notifyAll)的使用。
创建一个Condition

Condition需要被绑定在一个锁(Lock)上,所以如果要为一个Lock实例获得Condition实例,可以使用Lock的newCondition() 方法。

Condition notFull  = lock.newCondition(); 
Condition接口的常用方法
void await() 
造成当前线程在接到信号或被中断之前一直处于等待状态。
boolean await(long time, TimeUnit unit)
造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
long awaitNanos(long nanosTimeout)
造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
void awaitUninterruptibly()
造成当前线程在接到信号之前一直处于等待状态。
boolean awaitUntil(Date deadline)
造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。
void signal()
唤醒一个等待线程。
void signalAll()
唤醒所有等待线程。
代码示例

这段代码是JDK API文档中提供的示例,假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在多带带的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。

public class BoundedBuffer {

    final Lock lock = new ReentrantLock();
    final Condition notFull = lock.newCondition();
    final Condition notEmpty = lock.newCondition();

    final Object[] items = new Object[100];
    int putptr, takeptr, count;

    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length) {
                //当缓冲区已满时,notFull阻塞
                notFull.await();
            }
            //否则将元素添加进缓冲区的下标位置
            items[putptr] = x;
            if (++putptr == items.length) {
                //如果下一个下标越界,则将下标移至缓冲区首位
                putptr = 0;
            }
            //count表示缓冲区中元素个数
            ++count;
            //由于缓冲已经是notEmpty状态,所以唤醒阻塞等待的notEmpty
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) {
                //当缓冲区中没有元素,缓冲区处于empty状态,所以notEmpty阻塞
                notEmpty.await();
            }
            Object x = items[takeptr];
            if (++takeptr == items.length) {
                //获得下标位置的元素后,将下标向前移动,如果移动后的下标越界,则将下标移至缓冲区首位
                takeptr = 0;
            }
            --count;
            //取出一个元素后,缓冲区处于notFull状态,所以唤醒阻塞等待的notFull
            notFull.signal();
            return x;
        } finally {
            lock.unlock();
        }
    }
}
注意:

和监视器方法一样,Condition也可能发生“虚假唤醒”,所以Condition必须在总是在一个循环中被等待,并在被唤醒后测试当前状态,判断当前是否已经处于可以被唤醒的状态,我们需要假定“虚假唤醒”可能发生。

while (count == 0) {
    //在循环中等待
    condition.await();
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68809.html

相关文章

  • Java基础学习——线程线程间通信-生产者消费者代码示例)

    摘要:提供了多线程升级方案将同步替换成了显示的操作。线程间通信接口可以替代传统的线程间通信,用替换,用替换,用替换。商品执行上述代码,观察结果可以看到,多个线程同时生产消费,由于指定唤醒互异线程,因此并不会引起错误。 JDK 1.5提供了多线程升级方案将同步synchronized替换成了显示的Lock操作。可以实现唤醒、冻结指定的线程。 Lock接口Lock 实现提供了比使用 synchr...

    FuisonDesign 评论0 收藏0
  • Java 线程核心技术梳理(附源码)

    摘要:本文对多线程基础知识进行梳理,主要包括多线程的基本使用,对象及变量的并发访问,线程间通信,的使用,定时器,单例模式,以及线程状态与线程组。源码采用构建,多线程这部分源码位于模块中。通知可能等待该对象的对象锁的其他线程。 本文对多线程基础知识进行梳理,主要包括多线程的基本使用,对象及变量的并发访问,线程间通信,lock的使用,定时器,单例模式,以及线程状态与线程组。 写在前面 花了一周时...

    Winer 评论0 收藏0
  • Java线程进阶(二)—— J.U.C之locks框架:接口

    摘要:二接口简介可以看做是类的方法的替代品,与配合使用。当线程执行对象的方法时,当前线程会立即释放锁,并进入对象的等待区,等待其它线程唤醒或中断。 showImg(https://segmentfault.com/img/remote/1460000016012601); 本文首发于一世流云的专栏:https://segmentfault.com/blog... 本系列文章中所说的juc-...

    dkzwm 评论0 收藏0
  • 值得保存的 synchronized 关键字总结

    摘要:无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。另外在中引入了自适应的自旋锁。和关键字的总结推荐一 该文已加入开源文档:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识)。地址:https://github.com/Snailclimb... 本文是对 synchronized 关键字使用、底层原理、JD...

    miguel.jiang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<