并发编程系列之ReentrantLock用法简介

x33g5p2x  于2021-12-01 转载在 其他  
字(2.1k)|赞(0)|评价(0)|浏览(428)

并发编程系列之ReentrantLock用法简介

1、什么是ReentrantLock?

ReentrantLock是实现底层的Lock接口的可重入锁实现。支持公平锁模式和非公平锁模式。

典型例子:

  1. ReentrantLocl rlock = new ReentrantLock();
  2. try {
  3. rlock.lock();
  4. // 业务处理
  5. } finally {
  6. rlock.unlock();
  7. }

2、什么是重入锁和不可重入锁?

  1. 可重入锁:又称之为递归锁,也就是一个线程可以反复获取锁多次,一个线程获取到锁之后,内部如果还需要获取锁,可以直接再获取锁,前提是同一个对象或者class。ReentrantLock和synchronized都是可重入锁,可重入锁的最重要作用就是避免死锁的情况。
  2. 不可重入锁:又称之为自旋锁,底层是一个循环加上unsafe和cas机制,就是一直循环直到抢到锁,这个过程通过cas进行限制,如果一个线程获取到锁,cas (compareAndSet)会返回1,其它线程包括自己就不能再持有锁,需要等线程释放锁。

ReentrantLock是可重入锁,所以允许一个线程多次获取资源锁。第一次调用lock时,计数设置为1,再次获取资源锁时加1,调用unlock解锁,计数减1,直到减为0,释放锁资源,如图所示:

3、公平锁和非公平锁的区别?

  • 公平锁:多个线程按照申请锁的顺序去获取锁,线程会在队列里排队,按照顺序去获取锁。只有队列第1个线程才能获取到锁,获取到锁之后,其它线程都会阻塞等待,等到持有锁的线程释放锁,其它线程才会被唤醒。
  • 非公平锁:多个线程都会去竞争获取锁,获取不到就进入队列等待,竞争得到就直接获取锁;然后持有锁的线程释放锁之后,所有等待的线程就都会去竞争锁。
  1. // 设置ReentrantLock为公平锁
  2. ReentrantLock lock = new ReentrantLock(true);

4、ReentrantLock方法

在idea编辑器里查看ReentrantLock的方法:

挑一些常用方法进行描述

  • lock():如果共享资源最初是空闲的,调用lock会进行计数加1,并将锁提供给线程。会进行累加
  • unlock():调用unlock方法,会进行计数减1,减为0时,释放资源锁
  • tryLock():为了避免锁竞争,可以使用tryLock,如果资源没有被其他线程持有,会返回true,加锁成功,已经被其他线程持有了,返回false,加锁失败
  • tryLock(long timeout, TimeUnit unit):这个尝试加锁方法,多了一个超时时间
  • lockInterruptably():如果资源空闲,则此方法获取锁,允许该线程在获取资源时被其他线程中断。如果该线程在获取锁过程,其它线程抢进来,获取锁过程会被中断并立即返回而不获取锁
  • getHoldCount():此方法返回资源上持有的锁数的计数。
  • isHeldByCurrentThread():如果当前线程持有资源锁,则此方法返回true

5、ReentrantLock例子

  1. import java.util.concurrent.CountDownLatch;
  2. import java.util.concurrent.locks.ReentrantLock;
  3. public class ReentrantLockCountExample {
  4. private static volatile int count = 0;
  5. static ReentrantLock lock = new ReentrantLock();
  6. public static void countHandler() {
  7. lock.lock();
  8. try {
  9. count++;
  10. }finally {
  11. lock.unlock();
  12. }
  13. }
  14. public static void doCountConcurrent() throws InterruptedException {
  15. int threads = 20;
  16. CountDownLatch cdl = new CountDownLatch(threads);
  17. for (int i = 0; i < threads; i++) {
  18. new Thread(() -> {
  19. for (int n = 0; n < 10000; n++) {
  20. countHandler();
  21. }
  22. cdl.countDown();
  23. }).start();
  24. }
  25. try {
  26. cdl.await();
  27. } catch (InterruptedException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. public static void main(String[] args) throws InterruptedException {
  32. long start = System.currentTimeMillis();
  33. doCountConcurrent();
  34. System.out.println("统计耗时:" + (System.currentTimeMillis() - start) + "ms");
  35. System.out.println("result:"+ ReentrantLockCountExample.count);
  36. }
  37. }

相关文章