[TOC]
> ### `Lock`
* `synchronized`的缺陷,等待時間過長,需要有一種機制可以不讓等待的線程一直無期限地等待下去(比如只等待一定的時間或者能夠響應中斷),通過`Lock`就可以辦到。
* `Lock`不是Java語言內置的,`synchronized`是Java語言的關鍵字,因此是內置特性。`Lock`和`synchronized`有一點非常大的不同,采用`synchronized`不需要用戶去手動釋放鎖,當`synchronized`方法或者`synchronized`代碼塊執行完之后,系統會自動讓線程釋放對鎖的占用;而`Lock`則必須要用戶去手動釋放鎖,如果沒有主動釋放鎖,就有可能導致出現死鎖現象。
* `Lock`是一個接口,`ReentrantLock`是唯一實現了`Lock`接口的類。
* 不要將獲取鎖的過程寫在`try`塊中,因為如果在獲取鎖(自定義鎖的實現)時發生了異常,異常拋出的同時,也會導致鎖無故釋放。
<br/>
> ### `Lock`與`synchronized`比較

<br/>
> ### `Lock`接口的相關`api`

```
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