java除了使用关键字synchronized外,还可以使用ReentrantLock实现独占锁的功能。而且ReentrantLock相比synchronized而言功能更加丰富,使用起来更为灵活,也更适合复杂的并发场景。

一、简介

ReentrantLock常常对比着synchronized来分析,我们先对比着来看然后再一点一点分析。

  • synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。
  • synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。
  • synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以响应中断。

ReentrantLock好像比synchronized关键字没好太多,我们再去看看synchronized所没有的,一个最主要的就是ReentrantLock还可以实现公平锁机制。什么叫公平锁呢?也就是在锁上等待时间最长的线程将获得锁的使用权。通俗的理解就是谁排队时间最长谁先执行获取锁。

二、使用

1、简单使用

代码:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @description 可重入锁测试
* @author hzx
* @date 2022-04-01
*/
public class ReentrantLockTest {
private static final Lock lock = new ReentrantLock(); public static void main(String[] args) {
new Thread(() -> test(),"线程A").start();
new Thread(() -> test(),"线程B").start();
} public static void test() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"获取了锁");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName()+"释放了锁");
lock.unlock();
}
}
}

执行结果:

线程A获取了锁
线程A释放了锁
线程B获取了锁
线程B释放了锁

在这里我们定义了一个ReentrantLock,然后再test方法中分别lock和unlock,运行一边就可以实现我们的功能。这就是最简单的功能实现,代码很简单。我们再看看ReentrantLock和synchronized不一样的地方,那就是公平锁的实现。

2、公平锁实现

首先new一个ReentrantLock的时候参数为true,表明实现公平锁机制。公平锁的含义就是谁等的时间最长,谁就先获取锁。在这里我们多定义几个线程,然后在test方法中循环执行了两次加锁和解锁的过程。

代码:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @description 可重入锁测试(公平锁实现)
* @author hzx
* @date 2022-04-01
*/
public class ReentrantLockTest2 {
private static final Lock lock = new ReentrantLock(true); public static void main(String[] args) {
new Thread(() -> test(),"线程1").start();
new Thread(() -> test(),"线程2").start();
new Thread(() -> test(),"线程3").start();
new Thread(() -> test(),"线程4").start();
new Thread(() -> test(),"线程5").start();
} public static void test() {
for (int i = 0; i < 2; i++) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"获取了锁");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}

执行结果:

线程1获取了锁
线程2获取了锁
线程3获取了锁
线程4获取了锁
线程5获取了锁
线程1获取了锁
线程2获取了锁
线程3获取了锁
线程4获取了锁
线程5获取了锁
3、非公平锁实现

非公平锁那就随机的获取,谁运气好,cpu时间片轮到哪个线程,哪个线程就能获取锁,和上面公平锁的区别很简单,就在于先new一个ReentrantLock的时候参数为false,当然我们也可以不写,默认就是false。

代码:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @description 可重入锁测试(非公平锁实现)
* @author hzx
* @date 2022-04-01
*/
public class ReentrantLockTest3 {
private static final Lock lock = new ReentrantLock(false); public static void main(String[] args) {
new Thread(() -> test(),"线程1").start();
new Thread(() -> test(),"线程2").start();
new Thread(() -> test(),"线程3").start();
new Thread(() -> test(),"线程4").start();
new Thread(() -> test(),"线程5").start();
} public static void test() {
for (int i = 0; i < 2; i++) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"获取了锁");
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}

执行结果:

线程1获取了锁
线程2获取了锁
线程2获取了锁
线程3获取了锁
线程1获取了锁
线程3获取了锁
线程4获取了锁
线程4获取了锁
线程5获取了锁
线程5获取了锁

整个过程是随机的,没有固定的先后顺序,亲自测试时可以将for循环的次数增大,可以明显看出效果。

最新文章

  1. Hello, RealSense!
  2. 第三个Sprint总结
  3. javascript_core_08之闭包、对象、原型
  4. shell字符串操作详解
  5. Apache服务器配置默认首页文件名和网站路径
  6. uiscrollerview循环滚动(参考第三方库:HMBannerView)https://github.com/iunion/autoScrollBanner
  7. 写了一个jquery的 弹出层插件。
  8. 杭州网赛 two rabbits (hdu 4745)
  9. MySQL进程处于Waiting for table flush的分析
  10. python--第十八天总结(Django进阶)
  11. InternalError (see above for traceback): Blas GEMV launch failed: m=1, n=100
  12. SpringBoot2静态资料访问
  13. JavaScript -- Screen
  14. expect 交互 之双引号较长变量
  15. SQL Server从BAK文件还原新的数据库
  16. Android学习笔记——Menu(三)
  17. bzoj1093: [ZJOI2007]最大半连通子图 scc缩点+dag上dp
  18. 08day03
  19. html5大纲算法(目录树)
  20. 实践作业4:Web测试实践(小组作业)每日任务记录2

热门文章

  1. int 越界处理
  2. 纯css模拟电子钟
  3. HTML5与类有关的扩充
  4. CentOS的安装以及IP地址(动态/静态)的配置
  5. Blazor组件自做七 : 使用JS隔离制作定位/持续定位组件
  6. 【面试普通人VS高手系列】CPU飙高系统反应慢怎么排查?
  7. JavaScript学习①
  8. Python抽象基类:ABC谢谢你,因为有你,温暖了四季!
  9. IDEA编译项目后,target目录下的jsp文件不更新
  10. XSS攻击&amp;CSRF攻击 ----Django解决方案