java界面设计监视器_Java的对象监视器和Condition监视器概念以及对比

本文详细介绍了Java对象监视器的概念以及API方法,包括JDK1.5提供的Condition监视器对比。

1 对象监视器

对象监视器实际上就是与每个对象关联的Monitor对象,也叫做管程锁。实际上监视器也是一个数据结构,里面维护着一系列等待队列、同步队列等。这里不过多讨论对象监视器,详细讨论在会面的Synchronized部分中会有,本文主要针对Java初学者介绍相关的API方法,为后面的线程通信做准备,具体的应用将会在线程通信部分有讲到。

当多个线程持有的“对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象)同步代码块中的代码!可以是实现线程同步!

1.1 方法

为了方便线程协作通信,JAVA为提供了wait()和notifyAll以及notify()实现挂起线程,并且唤醒另外一个等待的线程的三个监视器方法(通知与等待)。

/**

* 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,能够使得当前线程进入等待队列,导致当前线程等待WAITING状态。该wait方法应由当前的持有对象监视器来调用。

* 想要唤醒该等待线程,也应该由其他持有相同的对象监视器的线程调用notify方法。即要求其他线程和需要被唤醒的等待线程持有相同的对象监视器。或者其他线程调用该线程的interrupt()方法, 该线程抛出InterruptedExce ption 异常返回。

* Wait的两个重载方法:

*/

public final void wait()

/**

* 限时等待timeout milliseconds(毫秒)

* @param timeout

*/

public final native void wait(long timeout)

/**

* 如果一个线程调用共享对象的该方法挂起后, 没有在指定的timeout ms 时间内被其他线程调用该共享变量的notify() 或者notifyAll() 方法唤醒,那么该函数还是会因为超时而返回。

* 如果将timeout 设置为0 则和wait 方法效果一样,因为在wait 方法内部就是调用了wait(O)。需要注意的是,如果在调用该函数时,传递了一个负的timeout 则会抛出IllegalArgumentException 异常。

*

* @param timeout

* @param nanos

*/

public final void wait(long timeout, int nanos)

/**

* 线程调用对象监视器的notify()方法,唤醒一条在该对象监视器上调用wait系列方法后被挂起的线程。如果有多条线程在同一等待队列中等待,只会选择唤醒其中一个线程,并且该选择是任意性的。

*/

public final void notify();

/**

* 调用notifyAll方法就可以唤醒对应对象监视器的等待队列当中所有的等待的线程。只对在该方法被调用之前等待的线程有效。

*/

public final void notifyAll();

1.2 特点

wait方法、notify方法、notifyAll方法,在使用的时候,必须要有自己的同步监视器(锁对象)。换句话:wait方法、notify方法、notifyAll方法,必须注册在某个同步监视器上(锁上)。(拥有自己的锁对象)否则抛出一个异常:IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。

因此创建了一个锁对象,这个锁对象上就具备一组监视器方法。Wait、notify、nofityAll方法就可以使用。

为什么上面的方法定义在Object类中?

wait、notify、nofityAll 监视器方法,在使用的时候,必须要由自己的锁对象来调用。锁对象是任意对象,Java中只要是对象均有一个自己的监视器对象,任意对象都能调用的方法就应该抽出来,定义在Object 类当中,毕竟Object是所有类型的超类!

1.3 Condition 监视器

1.3.1 Object的监视器方法与Condition接口的对比

任意一个Java对象,都拥有一与之关联的唯一的监视器对象,为此Java为每个对象提供了一组监视器方法(定义在java.lang.Object上),主要包括wait()、wait(long timeout)、notify()以及notifyAll()方法,这些方法与synchronized同步关键字配合,可以实现等待/通知模式。JDK1.5出现的Condition接口也提供了类似Object的监视器方法,与Lock配合可以实现等待/通知模式,但是这两者在使用方式以及功能特性上还是有差别的。Object的监视器方法与Condition接口的对比如下:

e9c2d04a8dfc5ba2154ccb243fda636d.png

Condition可以和任意的锁对象结合,监视器方法不会再绑定到某个锁对象上。使用Lock锁之后,相当于Lock 替代了synchronized方法和语句的使用,Condition替代了Object监视器方法的使用。

在Condition中,Condition对象当中封装了监视器方法,并用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式,Condition都可以实现,这里注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。

Condition的强大之处在于它可以为多个线程间建立不同的Condition,使用synchronized/wait()只有一个阻塞队列,notifyAll会唤起所有阻塞队列下的线程,而使用lock/condition,可以实现多个阻塞队列,signalAll只会唤起某个阻塞队列下的阻塞线程。

1.3.2 常用API方法

方法名称

描述

void await() throws InterruptedException

当前线程进入等待状态直到被通知(signal)或中断,当前线程进入运行状态且从await()方法返回的情况,包括1.其他线程调用该Condition的signal()活signalAll()方法,而当前线程被选中唤醒 2.其他线程(调用interrupt()方法)中断当前线程

void awaitUninterruptibly()

当前线程进入等待状态直到被通知,等待过程中不响应中断

long awaitNanos(long nanosTimeout) throws InterruptedException

当前线程进入等待状态直到被通知,中断,或者超时。返回值表示剩余的时间,如果在nanosTimeout纳秒之前被唤醒,那么返回值就是(nanosTimeout-实际耗时)。如果返回值是0或者负数,那么可以认定已经超时了

boolean await(long time, TimeUnit unit) throws InterruptedException

超时等待一段时间,如果没有通知就超时返回

boolean awaitUntil(Date deadline) throws InterruptedException

当前线程进入等待状态直到被通知,中断或者到某个时间。如果没有到指定时间就被通知,方法返回true,否则,表示到了指定时间,方法返回false

void signal()

唤醒一个等待在Condition上的线程,该线程从等待方法返回前必须获得与Condition相关联的锁

void signalAll()

唤醒所有等待在Condition上的线程,能够从等待方法返回的线程必须获得与Condition相关联的锁

注意:

获取一个Condition必须通过Lock的newCondition()方法。

Condition定义了等待/通知两种类型的方法,当前线程调用这些方法时,需要提前获取到Condition对象关联的锁。Condition对象是由Lock对象(调用Lock对象的newCondition()方法)创建出来的,换句话说,Condition是依赖Lock对象的。

本文同步分享在 博客“L-Java”(CSDN)。

如有侵权,请联系 support@oschina.cn 删除。

本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值