
Java并发编程——锁的等待与唤醒
发布日期:2021-05-07 08:40:41
浏览次数:26
分类:精选文章
本文共 4946 字,大约阅读时间需要 16 分钟。
1. wait和notify
1.1 使用场景
- 使用场景1:线程1
list
个数不等于5,就wait
;线程2添加元素,尽管个数大于5,notify
,但线程2继续持有锁,不会释放,所以线程1等线程2执行完才会输出
public class MyContainer2 { //添加volatile,使lists在其他线程可见 volatile List lists=new ArrayList(); public void add(Object o) { lists.add(o); } public int size() { return lists.size(); } public static void main(String[] args) { MyContainer2 c=new MyContainer2(); final Object lock=new Object(); new Thread(()->{ synchronized (lock) { System.out.println("t1 start"); if(c.size()!=5) { try { lock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("t1 end"); } },"t1").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } new Thread(()->{ System.out.println("t2 start"); synchronized (lock) { for(int i=0;i<10;i++) { c.add(new Object()); System.out.println("add "+i); if(c.size()>5) { lock.notify(); } try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } System.out.println("t2 end"); },"t2").start(); }}t1 startt2 startadd 0add 1add 2add 3add 4add 5add 6add 7add 8add 9t2 endt1 end
- 使用场景2:让线程2先释放锁,线程1执行完,再让线程2执行
public class MyContainer3 { //添加volatile,使lists在其他线程可见 volatile List lists=new ArrayList(); public void add(Object o) { lists.add(o); } public int size() { return lists.size(); } public static void main(String[] args) { MyContainer3 c=new MyContainer3(); final Object lock=new Object(); new Thread(()->{ synchronized (lock) { System.out.println("t1 start"); if(c.size()!=5) { try { lock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("t1 end"); //通知t1继续执行 lock.notify(); } },"t1").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } new Thread(()->{ System.out.println("t2 start"); synchronized (lock) { for(int i=0;i<10;i++) { c.add(new Object()); System.out.println("add "+i); if(c.size()==5) { lock.notify(); //让t2释放锁,让t1执行 try { lock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } System.out.println("t2 end"); },"t2").start(); }}
1.2 原理
使用 wait() 和 notify() 一定要放在同步代码块中,关联一个监视器对象,被 wait() 的线程会被记录到 Wait Set 等待队列中,被阻塞的线程会记录到 Entry Set 阻塞队列中
使用 notifyAll() :Wait Set 中被唤醒的线程会与 Entry Set 中被唤醒的线程以及其他(可能的)活跃线程共同参与抢夺锁资源。如果其中一个被唤醒的等待线程成功申请到锁,那么该线程就会从 Wait Set 中移除。否则,这些被唤醒的线程仍然停留在 Wait Set 中,并再次被暂停,以等待下次申请锁的机会。
public class Object { //... public final void wait() throws InterruptedException { wait(0); } public final native void wait(long timeout) throws InterruptedException; public final native void notify();}
2. await 和 signal
2.1 使用场景
public class MyContainer3 { final Lock lock = new ReentrantLock(); // condition 依赖于 lock 来产生 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.await(); // 队列已满,等待,直到 not full 才能继续生产 items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); // 生产成功,队列已经 not empty 了,发个通知出去 } finally { lock.unlock(); } } // 消费 public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); // 队列为空,等待,直到队列 not empty,才能继续消费 Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); // 被我消费掉一个,队列 not full 了,发个通知出去 return x; } finally { lock.unlock(); } }}
2.2 原理
public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); Condition newCondition();}public interface Condition { //... void await() throws InterruptedException; void signal();}
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2025年04月14日 14时33分12秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
使用async、await改善异步代码
2021-05-07
js-禁止右键菜单代码、禁止复制粘贴代码
2021-05-07
java 多态类型转换
2021-05-07
(C++11/14/17学习笔记):线程启动、结束,创建线程多法、join,detach
2021-05-07
HTML 和 CSS 简单实现注册页面
2021-05-07
趣谈win10常用快捷键
2021-05-07
11.2.6 时间值的小数秒
2021-05-08
Redis源码分析(七)--- zipmap压缩图
2021-05-08
【MySQL】(九)触发器
2021-05-08
Oracle 11G环境配置
2021-05-08
【Python】(十二)IO 文件处理
2021-05-08
【Oozie】(三)Oozie 使用实战教学,带你快速上手!
2021-05-08
师兄面试遇到这条 SQL 数据分析题,差点含泪而归!
2021-05-08
C语言的数值溢出问题(上)
2021-05-08
8051单片机(STC89C52)以定时器中断模式实现两倒计时器异步计时
2021-05-08
vue项目通过vue.config.js配置文件进行proxy反向代理跨域
2021-05-08
android:使用audiotrack 类播放wav文件
2021-05-08
聊聊我的五一小假期
2021-05-08