【多线程】可重入锁 ReentrantLock
2022/4/2 6:21:18
本文主要是介绍【多线程】可重入锁 ReentrantLock,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
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循环的次数增大,可以明显看出效果。
这篇关于【多线程】可重入锁 ReentrantLock的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享