Java锁系列教程之独占式锁
在Java并发编程中,锁是一个很重要的对象。Java中锁有两种:隐式锁和显式锁。使用synchronized关键字的锁是隐式锁。因为锁的申请和释放都是由JVM来维护的,不用我们来手动处理。使用Java并发包locks包下的锁,需要使用者手动申请和手动关闭。这种形式是显式锁。如果按照多个线程能不能共享同一个锁(资源)来分的话,可以分为独占式(排他)锁和共享锁。其中synchronized关键字的锁和ReentrantLock锁的锁都是独占式锁。
通过前面三篇文章的学习,我们知道了同步组件基础框架-AbstractQueuedSynchronizer(AQS) 同步器。在同步器的方法中有两种方式获取锁:独占式和共享式锁。我们先来学习独占式锁-ReentrantLock。
本篇是《凯哥(凯哥Java:kagejava)并发编程学习》系列之《Lock系列》教程的第四篇:《Java并发包下锁学习第四篇:ReentrantLock》。
编辑
ReentrantLock使用语法
我们知道并发包下的lock是显式锁,需要手动获取锁和手动释放锁。所以语法如下:
ReentrantLock lock = new ReentrantLock();
try {
lock.lock();
//TODO
}finally {
lock.unlock();
}
获取锁:lock.lock();
释放锁:lock.unlock();
在try中获取到锁;在finally中释放锁。
因为必须释放锁。所以,必须在finally中进行释放锁操作。而且释放锁操作必须放在finally的第一行。
独占式锁理解:
生活中的例子:
在自动ATM机上取钱的时候,我们需要排队,当一个人在操作ATM机取钱的时候,下一个人就需要在ATM机黄线外面等待(排除和取钱人一起去的人)。假设路人甲在操作ATM机的时候,我们其他后面排队的人是不是需要等待着,路人甲从ATM机区域出来后才可以进行操作ATM机。这个操作过程如果放在我们多线程并发角度来思考的话:共享数据是ATM机,多个线程是多个存取钱的人。当路人甲在操作ATM机的时候路人甲获取到ATM机操作权限可以理解为lock.lock()操作。这个时候,共享数据ATM机就会被路人甲独自一个人占用了(独占式获取到了共享数据(或者是锁))。当路人甲操作完离开ATM机这个操作可以理解为lock.unlock()操作。
从上了生活例子中我们可以这么理解独占式锁,所谓的独占式锁就是同一时刻只能有且只有一个线程获取到锁且操作成功,其他线程只能等待释放锁后,在进行操作。
需要说明的是,在Java中隐式锁(synchronized关键字修饰的)也是独占式锁的一种体现。
使用方法一:独占非公平演示
需求:使用三个线程,调用一个方法,在方法内睡眠2s.代码下图:
查看运行结果:
线程2开始获取锁。
线程3开始获取锁。
线程1开始获取锁。
线程2获取到了锁。开始做其他的操作了====do..........
======关闭锁=======
线程3获取到了锁。开始做其他的操作了====do..........
======关闭锁=======
线程1获取到了锁。开始做其他的操作了====do..........
======关闭锁=======
从上图运行结果,我们可以分析出:
1:线程的顺序和我们线程运行的顺序不一致
2:每次只能有一个线程执行完关闭锁之后,其他线程才可以接着使用。
从示例代码,我们可以得到如下总结:
1:reentrantLock是独占式锁;
2:默认情况下不能保证获取锁的顺序和线程执行顺序的一致性。
如果想要保证线程执行顺序和获取锁的顺序一致性,也是可以操作的。在下一篇文章中,凯哥将讲解怎么操作。
欢迎来聊