JUC并发编程

LockSupport

1. LockSupport是什么

  1. LockSupport是用于创建锁和其他同步类基本线程阻塞原语
  2. LockSupport没有构造函数,说明不可以new对象,只可以使用静态方法
  3. 核心方法就是 park() 和 unpark()
  4. park()除非许可证可用,否则禁用当前线程
  5. unpark(Thread):如果给定线程不可用,则为其提供许可
  6. park()和unpark()分别是阻塞线程解除被阻塞的线程
  7. LockSupport就是对线程等待唤醒机制(wait()/notify())的优化

2. 线程等待唤醒机制

  1. 使用Object中的wait()让线程等待,使用notify()唤醒等待的线程
    1. 通过调用对象的wait()来阻塞,然后再调用该对象的notify()来唤醒被阻塞的线程
    2. wait()方法会释放当前对象的锁,会释放当前对象的锁,而sleep()方法不会释放调用对象的锁
    3. wait 方法释放了锁,但是t1线程是阻塞状态不可以争夺cpu时间片,当t2线程notify之后唤醒t1线程并进入就绪态后才可以争夺cpu时间片进行运行
    4. 如果要使用wait()和notify(),必须要包在Synchronized代码块内
    5. 必须在获得某个对象的锁之后,才可以调用该对象的wait()和notify()方法来阻塞唤醒线程,故wait和notify必须在Synchronized代码块或者方法内,且使用锁对象调用
    6. 通过对象的wait()和notify()可以实现线程阻塞和唤醒,但必须是同一个对象才可以唤醒被阻塞的线程,且必须获得对象的锁之后才可以调用对象的wait()和notify()方法来阻塞唤醒线程
    7. 且如果使用对象的wait()和notify()来阻塞唤醒线程,则此时如果顺序出错,则会导致线程一直阻塞,必须先获得对象的锁之后,才可以调用对象的wait和notify来阻塞唤醒线程,且wait会释放当前对象的锁
    8. 必须保证wait之后再notify,否则会出现线程一直阻塞现象,不是死锁,因为只有一个线程一直阻塞
    9. 死锁是两个或以上线程因为竞争资源而造成的相互等待现象
  2. 使用JUC包中Lock锁对象的Condition的await()让线程等待,使用signal()唤醒线程
    1. 通过对象的wait()和notify()可以实现线程的阻塞和唤醒,但必须保证先获得对象的锁,即必须在Synchronized代码块中;且必须保证先wait之后再notify,否则会导致一直阻塞
    2. 通过Lock锁对象.newCondition()创建Condition对象,然后通过c1.await()阻塞线程,再通过c1.signal()唤醒被阻塞的线程
    3. 通过JUC中Lock锁对象自带的Condition的await()和signal()也可以实现线程的噪声和唤醒
    4. 使用Condition对象阻塞唤醒线程时,依旧要确保先加锁,必须先获得创建Condition对象的Lock锁之后才可以使用该Condition对象的await和signal;Condition的await和signal也必须在lock和unLock锁块之中使用
    5. 且必须要保证先await()阻塞线程之后再signal()唤醒线程,否则会导致线程一直阻塞,此时不是死锁,因为只有一个线程阻塞,而不是两个或以上相互竞争资源
  3. 使用LockSupport的park()阻塞线程,使用unpark()唤醒线程
    1. 使用Object对象的wait()和notify()或者使用Condition对象的await()和signal()可以实现线程阻塞唤醒机制,但都必须满足必须先加锁,然后才可以调用方法;且必须先阻塞后再唤醒,保证顺序不变,否则会导致线程一直阻塞
    2. LockSupport的park()和unpark()也可以实现线程的噪声和唤醒,且park()是当没有许可时阻塞线程,而unpark(Thread)是如果线程没有许可则给其许可,且通过LockSupport的静态方法来调用,故此时不需要先加锁,而且可以先unpark()后再park()
    3. LockSupport是创建锁和其他同步类的基本线程阻塞原语,通过park()和unpark()来阻塞和唤醒线程,且使用Permit许可来做到阻塞和唤醒线程,每一个线程都有最多一个许可,如果存在许可证,则park()不会阻塞,且会消耗许可证;最多只可以拥有一个许可证,且每次park都会消耗一个许可证,且许可证不可以累积,通过unpark(Thread)来获得许可证
    4. LockSupport的park()调用的是UNSAFE类的park(boolean,time阻塞时间),其底层调用的是native的park(),且当线程没有许可时就会阻塞time时间,此时就需要别的线程通过unpark(thread)来给线程许可来唤醒
    5. 当线程调用LockSupport.park()后,如果该线程没有许可,则会阻塞,直到其他线程通过unpark(thread)给指定线程一个许可后才可以使其唤醒;每一个线程最多只可以有一个许可,且每次park()都会消耗一个许可
    6. Java底层是使用C++实现
    7. 如果使用Object对象的wait()/notify(),或者使用JUC中的Condition对象的await()和signal()实现线程阻塞和唤醒时,此时必须要先获得锁对象,即必须在锁块中才可以调用函数,且必须保证先阻塞再唤醒;为了克服这些限制,可以使用LockSupport的park()和unpark()来实现线程阻塞和唤醒,此时不需要在锁块中调用,直接使用LockSupport的静态方法,且不需要保证调用顺序,因为其是使用permit许可来实现的
    8. LockSupport不需要先加锁直接就可以实现线程的阻塞和唤醒,不需要先加锁,直接进行线程阻塞和唤醒,通过LockSupport.park()来加锁,通过LockSupport.unpark(Thread)来对线程唤醒,park()会消耗permit许可,而unpark()会增加许可,最多只可以有一个许可
    9. LockSuport不需要先加锁,而且可以先唤醒再阻塞,顺序相反不会影响
    10. 使用LockSupport时不需要关注执行顺序,顺序相反仍可以实现,此时可以确保某个代码执行完成后再让另一个代码执行

3. LockSupport

  1. LockSupport通过许可来实现阻塞和唤醒,且每一个线程最多只有一个许可,此时unpark()后不会再增加许可
  2. LockSupport是创建锁和其他类的线程阻塞原语,是线程阻塞的工具类,与Object的wait/notify以及Condition的await/signal相比,不需要先加锁,而且唤醒和阻塞顺序不影响最终结果通过静态方法park()和unpark(thread)来实现阻塞和唤醒;通过permit许可来实现,且每一个线程最多只可以有一个许可,且每次park()均会消耗一个许可,如果没有许可时就会阻塞,此时必须让别的线程通过unpark来给其许可才会唤醒
  3. Object和Condition的线程阻塞唤醒机制,必须先获得对应对象的锁,然后调用同一个对象的阻塞和唤醒方法才可以实现线程阻塞和唤醒
  4. 每一个线程最多只可以有一个许可,故多次unpark()的结果是一样的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值