java lock signal方法_java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)...

一、Condition 类

在前面我们学习与synchronized锁配合的线程等待(Object.wait)与线程通知(Object.notify),那么对于JDK1.5 的

java.util.concurrent.locks.ReentrantLock 锁,JDK也为我们提供了与此功能相应的类java.util.concurrent.locks.Condition。Condition与重入锁是通过lock.newCondition()方法产生一个与当前重入锁绑定的

Condtion实例,我们通知该实例来控制线程的等待与通知。该接口的所有方法:

复制代码

public interface Condition {

//使当前线程加入 await() 等待队列中,并释放当锁,当其他线程调用signal()会重新请求锁。与Object.wait()类似。

void await() throws InterruptedException;

//调用该方法的前提是,当前线程已经成功获得与该条件对象绑定的重入锁,否则调用该方法时会抛出IllegalMonitorStateException。

//调用该方法后,结束等待的唯一方法是其它线程调用该条件对象的signal()或signalALL()方法。等待过程中如果当前线程被

中断,该方法仍然会继续等待,同时保留该线程的中断状态。

void awaitUninterruptibly();

// 调用该方法的前提是,当前线程已经成功获得与该条件对象绑定的重入锁,否则调用该方法时会抛出IllegalMonitorStateException。

//nanosTimeout指定该方法等待信号的的最大时间(单位为纳秒)。若指定时间内收到signal()或signalALL()则返回nanosTimeout减去已经等待的时间;

//若指定时间内有其它线程中断该线程,则抛出InterruptedException并清除当前线程的打断状态;若指定时间内未收到通知,

则返回0或负数。

long awaitNanos(long nanosTimeout) throws InterruptedException;

//与await()基本一致,唯一不同点在于,指定时间之内没有收到signal()或signalALL()信号或者线程中断时该方法会返回

false;其它情况返回true。

boolean await(long time, TimeUnit unit) throws InterruptedException;

//适用条件与行为与awaitNanos(long nanosTimeout)完全一样,唯一不同点在于它不是等待指定时间,而是等待由参数指定的

某一时刻。

boolean awaitUntil(Date deadline) throws InterruptedException;

//唤醒一个在 await()等待队列中的线程。与Object.notify()相似

void signal();

//唤醒 await()等待队列中所有的线程。与object.notifyAll()相似

void signalAll();

}

复制代码

二、使用

1、await() 等待 与 singnal()通知

复制代码

1 package com.jalja.org.base.Thread;

2

3 import java.util.concurrent.TimeUnit;

4 import java.util.concurrent.locks.Condition;

5 import java.util.concurrent.locks.ReentrantLock;

6

7 /**

8 * Condition 配合Lock 实现线程的等待 与通知

9 */

10 public class ConditionTest{

11 public static ReentrantLock lock=new ReentrantLock();

12 public static Condition condition =lock.newCondition();

13 public static void main(String[] args) {

14 new Thread(){

15 @Override

16 public void run() {

17 lock.lock();//请求锁

18 try{

19 System.out.println(Thread.currentThread().getName()+"==》进入等待");

20 condition.await();//设置当前线程进入等待

21 }catch (InterruptedException e) {

22 e.printStackTrace();

23 }finally{

24 lock.unlock();//释放锁

25 }

26 System.out.println(Thread.currentThread().getName()+"==》继续执行");

27 }

28 }.start();

29 new Thread(){

30 @Override

31 public void run() {

32 lock.lock();//请求锁

33 try{

34 System.out.println(Thread.currentThread().getName()+"=》进入");

35 Thread.sleep(2000);//休息2秒

36 condition.signal();//随机唤醒等待队列中的一个线程

37 System.out.println(Thread.currentThread().getName()+"休息结束");

38 }catch (InterruptedException e) {

39 e.printStackTrace();

40 }finally{

41 lock.unlock();//释放锁

42 }

43 }

44 }.start();

45 }

46 }

复制代码

执行结果:

Thread-0==》进入等待

Thread-1=》进入

Thread-1休息结束

Thread-0==》继续执行

流程:在调用await()方法前线程必须获得重入锁(第17行代码),调用await()方法后线程会释放当前占用的锁。同理在调用

signal()方法时当前线程也必须获得相应重入锁(代码32行),调用signal()方法后系统会从condition.await()等待队列中唤醒一

个线程。当线程被唤醒后,它就会尝试重新获得与之绑定的重入锁,一旦获取成功将继续执行。所以调用signal()方法后一定要释放当

前占用的锁(代码41行),这样被唤醒的线程才能有获得锁的机会,才能继续执行。

三、JDK中对Condition 的使用

我们来看看java.util.concurrent.ArrayBlockingQueue;

基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞

队列,除了一个定长数组外,ArrayBlockingQueue内部还保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。

看看他的put方法:

复制代码

public void put(E e) throws InterruptedException {

checkNotNull(e);//对传入元素的null判断

final ReentrantLock lock = this.lock;

lock.lockInterruptibly();//对put()方法做同步

try {

while (count == items.length)//如果队列已满

notFull.await();//让当前添加元素的线程进入等待状态

insert(e);// 如果有其他线程调用signal() 通知该线程 ,则进行添加行为

} finally {

lock.unlock();//释放锁

}

}

private E extract() {

final Object[] items = this.items;

E x = this.cast(items[takeIndex]);

items[takeIndex] = null;

takeIndex = inc(takeIndex);

--count;

notFull.signal();//唤醒一个在Condition等待队列中的线程

return x;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值