[TOC]
> ### `Lock`
* `synchronized`的缺陷,等待时间过长,需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过`Lock`就可以办到。
* `Lock`不是Java语言内置的,`synchronized`是Java语言的关键字,因此是内置特性。`Lock`和`synchronized`有一点非常大的不同,采用`synchronized`不需要用户去手动释放锁,当`synchronized`方法或者`synchronized`代码块执行完之后,系统会自动让线程释放对锁的占用;而`Lock`则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
* `Lock`是一个接口,`ReentrantLock`是唯一实现了`Lock`接口的类。
* 不要将获取锁的过程写在`try`块中,因为如果在获取锁(自定义锁的实现)时发生了异常,异常抛出的同时,也会导致锁无故释放。
<br/>
> ### `Lock`与`synchronized`比较
![](https://i.loli.net/2019/03/11/5c85d58d81a5a.png)
<br/>
> ### `Lock`接口的相关`api`
![](https://i.loli.net/2019/03/11/5c85d52e252f0.png)
```
public class Test {
private ArrayList<Integer> arrayList = new ArrayList<Integer>();
private Lock lock = new ReentrantLock(); //注意这个地方
public static void main(String[] args) {
final Test test = new Test();
new Thread(){
public void run() {
test.insert(Thread.currentThread());
};
}.start();
new Thread(){
public void run() {
test.insert(Thread.currentThread());
};
}.start();
}
public void insert(Thread thread) {
//加锁
lock.lock();
try {
System.out.println(thread.getName()+"得到了锁");
for(int i=0;i<5;i++) {
arrayList.add(i);
}
} catch (Exception e) {
// TODO: handle exception
}finally {
System.out.println(thread.getName()+"释放了锁");
//释放锁
lock.unlock();
}
}
}
```
<br/>
> ### `ReentrantLock`
<br/>
> ### `Condition`
* `Condition`定义了等待/通知两种类型的方法,当前线程调用这些方法时,需要提前获取到`Condition`对象关联的锁。`Condition`对象是由`Lock`对象(调用`Lock`对象的`newCondition()`方法)创建出来的,换句话说,`Condition`是依赖`Lock`对象的。
* 一般都会将`Condition`对象作为成员变量。当调用`await()`方法后,当前线程会释放锁并在此等待,而其他线程调用`Condition`对象的`signal()`方法,通知当前线程后,当前线程才从`await()`方法返回,并且在返回前已经获取了锁。
> ### 三个线程 循环打印 ABC `lock condition`
```
public class LockConditionABC_3 {
// lock condition 三个线程 循环打印 ABC
// 参考 https://www.bbsmax.com/A/amd0ENEWzg/
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();
Thread t1 = new Thread(new ThreadDemo(lock, conditionA, conditionB, 'A'), "ThreadA");
Thread t2 = new Thread(new ThreadDemo(lock, conditionB, conditionC, 'B'), "ThreadB");
Thread t3 = new Thread(new ThreadDemo(lock, conditionC, conditionA, 'C'), "ThreadC");
t1.start();
Thread.sleep(100);
t2.start();
Thread.sleep(100);
t3.start();
}
static class ThreadDemo implements Runnable{
private final ReentrantLock reentrantLock;
private final Condition thisCondtion;
private final Condition nextCondtion;
Character c;
public ThreadDemo(ReentrantLock reentrantLock, Condition thisCondtion, Condition nextCondition, char c) {
this.reentrantLock = reentrantLock;
this.nextCondtion = nextCondition;
this.thisCondtion = thisCondtion;
this.c = c;
}
public void run(){
reentrantLock.lock();
try {
// 连续打印
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ":" + c);
// 使用nextCondition唤醒下一个线程
// 因为只有一个线程在等待,所以signal或者signalAll都可以
nextCondtion.signal();
// 不是最后一次则通过thisCondtion等待被唤醒
// 必须要加判断,不然能够打印6次 但6次后就会直接死锁
if (i < 5 - 1) {
try {
// 本线程让出锁并等待唤醒
thisCondtion.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} finally {
// 释放锁
reentrantLock.unlock();
}
}
}
}
```
<br/>
> ### `ReadWriteLock`
* `ReadWriteLock`也是一个接口,`ReentrantReadWriteLock`是其的实现类,主要有两个方法:`readLock()`和`writeLock()`用来获取读锁和写锁。
* 读是共享读锁,写是独占锁阻塞其它的读写操作
```
public class ReentrantReadWriteLockDemo {
private static final Map<String, Object> map = new HashMap<String, Object>();
private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private static final Lock readLock = lock.readLock();
private static final Lock writeLock = lock.writeLock();
public ReentrantReadWriteLockDemo() {
if(map.size() == 0 ) map.put("0", "asd");
}
//读写锁
//在同一时刻允许多个线程进行读操作
//但是有线程进行写操作时,阻塞其它线程的读写
public final Object get(String key, int threadId) {
readLock.lock();
try {
System.out.println("Thread: " + threadId + " > read " + key + "|" + map.get(key));
return map.get(key);
} finally {
readLock.unlock();
}
}
public final Object put(String key, Object value, int threadId) {
writeLock.lock();
try {
System.out.println("Thread: " + threadId + " > write " + key + " | " + value);
SleepUtils.second(1000);
return map.put(key, value);
} finally {
writeLock.unlock();
}
}
public final void clear() {
writeLock.lock();
try {
map.clear();
} finally {
writeLock.unlock();
}
}
public static void main(String[] args) {
ReentrantReadWriteLockDemo demo = new ReentrantReadWriteLockDemo();
for(int i = 0; i < 30; i++){
Thread thread = new Thread(new ThreadDemo(demo), String.valueOf(i));
thread.start();
}
}
public static class ThreadDemo implements Runnable{
ReentrantReadWriteLockDemo demo ;
public ThreadDemo(ReentrantReadWriteLockDemo demo){
this.demo = demo;
}
public void run() {
int i = Integer.valueOf(Thread.currentThread().getName());
if(i % 10 == 0){
demo.put(String.valueOf(i), Thread.currentThread().getName(), i);
}else{
demo.get(String.valueOf(0), i);
}
}
}
static class SleepUtils{
public static void second(int i){
try {
Thread.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
```
<br/>
<br/>
***
参考:
[ReentrantLock(重入锁)以及公平性](http://ifeve.com/reentrantlock-and-fairness/)
- asD
- Java
- Java基础
- Java编译器
- 反射
- collection
- IO
- JDK
- HashMap
- ConcurrentHashMap
- LinkedHashMap
- TreeMap
- 阻塞队列
- java语法
- String.format()
- JVM
- JVM内存、对象、类
- JVM GC
- JVM监控
- 多线程
- 基础概念
- volatile
- synchronized
- wait_notify
- join
- lock
- ThreadLocal
- AQS
- 线程池
- Spring
- IOC
- 特性介绍
- getBean()
- creatBean()
- createBeanInstance()
- populateBean()
- AOP
- 基本概念
- Spring处理请求的过程
- 注解
- 微服务
- 服务注册与发现
- etcd
- zk
- 大数据
- Java_spark
- 基础知识
- Thrift
- hdfs
- 计算机网络
- OSI七层模型
- HTTP
- SSL
- 数据库
- Redis
- mysql
- mybatis
- sql
- 容器
- docker
- k8s
- nginx
- tomcat
- 数据结构/算法
- 排序算法
- 快排
- 插入排序
- 归并排序
- 堆排序
- 计算时间复杂度
- leetcode
- LRU缓存
- B/B+ 树
- 跳跃表
- 设计模式
- 单例模式
- 装饰者模式
- 工厂模式
- 运维
- git
- 前端
- thymeleaf
- 其他
- 代码规范
- work_project
- Interview