结合Object上的wait和notify方法可以实现线程间的等待通知机制。
1:结合Condition接口同样可以实现这个功能。而且相比前 者使用起来更清晰也更简单。
2:ReentrantLock可以创建Condition对象,供调用者添加不同的条件队列,实现更灵活多样化的等待机制
1.Condition能够支持不响应中断,而通过使用Object方式不支持
2.Condition能够支持多个等待队列(new 多个Condition对象),而Object方式只能支持一个
3.Condition能够支持超时时间的设置(超时自动唤醒),而Object不支持
- package com.lock;
-
- import org.apache.log4j.Logger;
-
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.ReentrantLock;
-
- public class AwaitTest1 {
-
- static ReentrantLock lock = new ReentrantLock();
- static Condition condition = lock.newCondition();
- static Logger log = Logger.getLogger(AwaitTest1.class);
- public static void main(String[] args) throws InterruptedException {
- new Thread("t1"){
- public void run() {
- try {
- lock.lock();
- log.debug(Thread.currentThread().getName()+"因为某些条件无法满足,进入等待");
- condition.await(); //进入等待
- log.debug(Thread.currentThread().getName()+"条件满足了被唤醒,开始工作");
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- }.start();
-
- TimeUnit.SECONDS.sleep(4);
- //main线程负责唤醒t1
- lock.lock();
- condition.signal();//唤醒
- lock.unlock();
- }
- }
- /**
- * 此时的结果4秒后,主线程将t1线程唤醒,t1线程就继续执行后面的逻辑啦,打印了开始工作
- */
- package com.lock;
-
- import org.apache.log4j.Logger;
-
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.ReentrantLock;
-
- public class AwaitTest2 {
- static ReentrantLock lock = new ReentrantLock();
- static Condition condition = lock.newCondition();
- static Logger log = Logger.getLogger(AwaitTest2.class);
- public static void main(String[] args) throws InterruptedException {
- Thread thread = new Thread("t1"){
- public void run() {
- try {
- lock.lock();
- log.debug(Thread.currentThread().getName()+"因为某些条件无法满足,进入等待");
- // condition.await(); //进入等待(t1线程被打断会抛出中断异常)
- condition.awaitUninterruptibly(); //进入等待(t1线程被打断不会抛出中断异常)
- log.debug(Thread.currentThread().getName()+"条件满足了被唤醒,开始工作");
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- };
- thread.start();
- TimeUnit.SECONDS.sleep(4);
- thread.interrupt();//打断t1线程
- log.debug(Thread.currentThread().getName()+"打断t1线程");
- }
- }
总结
上面的两个方法在不发生异常的情况下,会一直在等待被其他线程唤醒。接下来的三个方法,都是带有时间的等待,在一个时间范围内等待,超过这个时间范围,那么就会自己醒来。
- package com.condition;
-
- import org.apache.log4j.Logger;
-
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.ReentrantLock;
-
- public class AwaitTest3 {
-
- static ReentrantLock lock = new ReentrantLock();
- static Condition condition = lock.newCondition();
- static Logger log = Logger.getLogger(AwaitTest3.class);
- public static void main(String[] args) throws InterruptedException {
-
- Thread thread = new Thread("t1"){
- public void run() {
- try {
- lock.lock();
- log.debug(Thread.currentThread().getName()+"因为某些条件无法满足,进入等待");
- condition.awaitNanos(5000000000l);//5秒,单位是纳秒
- log.debug(Thread.currentThread().getName()+"没人人唤醒我,超时了,自己醒来开始工作");
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- };
- thread.start();
- }
- }
超过截止时间等待后释放后自动唤醒
ReentrantLock还给我们提供了获取锁超时等待的方法tryLock()
,可以选择传入时间参数,表示指定等待的时间,无参则表示立即返回申请锁的boolean结果;
设置让线程等待的时间,这个时间之后再获取锁
- package com.lock;
-
- import org.apache.log4j.Logger;
-
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.locks.ReentrantLock;
-
- public class LockTest5 {
- static ReentrantLock lock = new ReentrantLock();
- static Logger log = Logger.getLogger(LockTest5.class);
- public static void main(String[] args) throws InterruptedException {
- Thread t1 = new Thread(){
- public void run(){
- log.debug("t1启动---------");
- try {
- if (!lock.tryLock(2, TimeUnit.SECONDS)) {//尝试获取锁,如果获取失败则返回
- log.debug("t1拿不到锁,返回");
- return;
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- log.debug("t1获得了锁");
- lock.unlock();
- log.debug("t1释放了锁");
- }};
- //主线程获得了锁
- lock.lock();
- log.debug("主线程获得了锁");
- t1.start();
-
- try {
- TimeUnit.SECONDS.sleep(3);
- log.debug("主线程休眠3秒钟");
- } finally {
- lock.unlock();
- log.debug("主线程释放了锁");
- }
-
- }
- }