ReentrantLock的使用
一、初識ReentrantLock
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by haicheng.lhc on 17/05/2017.
*
* @author haicheng.lhc
* @date 2017/05/17
*/
public class ReentrantLockTest extends Thread {
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0;
public ReentrantLockTest(String name) {
super.setName(name);
}
@Override
public void run() {
for (int j = 0; j < 10000000; j++) {
lock.lock();
try {
System.out.println(this.getName() + " " + i);
i++;
} finally {
lock.unlock();
}
}
}
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
ReentrantLockTest test1 = new ReentrantLockTest("thread1");
ReentrantLockTest test2 = new ReentrantLockTest("thread2");
test1.start();
test2.start();
test1.join();
test2.join();
System.out.println(i);
}
}
最後的結果是
20000000
;如果去掉鎖,那麼輸出結果是一個小於20000000
的不確定的數
二、ReentrantLock的優點
- java中已經有了內建鎖:
synchronized
,synchronized
的特點是使用簡單,一切交給JVM去處理,不需要顯示釋放 - 從用法上可以看出,與
synchronized
相比,ReentrantLock
就稍微複雜一點。因為必須在finally中進行解鎖操作,如果不在 finally解鎖,有可能程式碼出現異常鎖沒被釋放,
那麼為什麼要引入ReentrantLock呢?
- 在jdk1.5裡面,
ReentrantLock
的效能是明顯優於synchronized
的,但是在jdk1.6裡面,synchronized
做了優化,他們之間的效能差別已經不明顯了。
-
ReentrantLock
並不是一種替代內建加鎖的方法,而是作為一種可選擇的高階功能。 - 相比於
synchronized
,ReentrantLock
在功能上更加豐富,它具有可重入、可中斷、可限時、公平鎖等特點。
ReentrantLock 實現了 Lock interface
可重入(其實synchronized 也是可重入的)
lock.lock();
lock.lock();
try
{
i++;
}
finally
{
lock.unlock();
lock.unlock();
}
由於
ReentrantLock
是重入鎖,所以可以反覆得到相同的一把鎖,它有一個與鎖相關的獲取計數器,如果擁有鎖的某個執行緒再次得到鎖,那麼獲取計數器就加1,然後鎖需要被釋放兩次才能獲得真正釋放(重入鎖)。
可中斷
- 與
synchronized
不同的是,ReentrantLock
對中斷是有響應的.synchronized
一旦嘗試獲取鎖就會一直等待直到獲取到鎖。
構造一個死鎖的例子,然後用中斷來處理死鎖
package concurrency.in.practice;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by haicheng.lhc on 17/05/2017.
*
* @author haicheng.lhc
* @date 2017/05/17
*/
public class LockInterrupt extends Thread {
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock;
public LockInterrupt(int lock, String name) {
super(name);
this.lock = lock;
}
@Override
public void run() {
try {
if (lock == 1) {
lock1.lockInterruptibly();
try {
Thread.sleep(500);
} catch (Exception e) {
// TODO: handle exception
}
lock2.lockInterruptibly();
} else {
lock2.lockInterruptibly();
try {
Thread.sleep(500);
} catch (Exception e) {
// TODO: handle exception
}
lock1.lockInterruptibly();
}
} catch (Exception e) {
// TODO: handle exception
} finally {
if (lock1.isHeldByCurrentThread()) {
lock1.unlock();
}
if (lock2.isHeldByCurrentThread()) {
lock2.unlock();
}
System.out.println(Thread.currentThread().getId() + ":執行緒退出");
}
}
public static void main(String[] args) throws InterruptedException {
LockInterrupt t1 = new LockInterrupt(1, "LockInterrupt1");
LockInterrupt t2 = new LockInterrupt(2, "LockInterrupt2");
t1.start();
t2.start();
Thread.sleep(1000);
//DeadlockChecker.check();
}
static class DeadlockChecker {
private final static ThreadMXBean mbean = ManagementFactory
.getThreadMXBean();
public static void check() {
Thread tt = new Thread(() -> {
{
// TODO Auto-generated method stub
while (true) {
long[] deadlockedThreadIds = mbean.findDeadlockedThreads();
if (deadlockedThreadIds != null) {
ThreadInfo[] threadInfos = mbean.getThreadInfo(deadlockedThreadIds);
for (Thread t : Thread.getAllStackTraces().keySet()) {
for (int i = 0; i < threadInfos.length; i++) {
if (t.getId() == threadInfos[i].getThreadId()) {
System.out.println(t.getName());
t.interrupt();
}
}
}
}
try {
Thread.sleep(5000);
} catch (Exception e) {
// TODO: handle exception
}
}
}
});
tt.setDaemon(true);
tt.start();
}
}
}
執行後,確實出現了死鎖,使用jstack可以看到如下結果:
通過中斷來停止執行緒,結果如下:
可限時
超時不能獲得鎖,就返回false,不會永久等待構成死鎖
使用
lock.tryLock(long timeout, TimeUnit unit)
來實現可限時鎖,引數為時間和單位。
例子
package concurrency.in.practice;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by haicheng.lhc on 17/05/2017.
*
* @author haicheng.lhc
* @date 2017/05/17
*/
public class TryLockTest extends Thread {
public static ReentrantLock lock = new ReentrantLock();
public TryLockTest(String name){
super(name);
}
@Override
public void run() {
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
Thread.sleep(6000);
} else {
System.out.println(this.getName() + " get lock failed");
}
} catch (Exception e) {
} finally {
if (lock.isHeldByCurrentThread()) {
System.out.println("lock.isHeldByCurrentThread: " + this.getName());
lock.unlock();
}
}
}
public static void main(String[] args) {
TryLockTest t1 = new TryLockTest("TryLockTest1");
TryLockTest t2 = new TryLockTest("TryLockTest2");
t1.start();
t2.start();
}
}
輸出結果:
兩個執行緒來爭奪一把鎖,獲得鎖的執行緒sleep6秒,每個執行緒都只嘗試5秒去獲得鎖。
所以必定有一個執行緒無法獲得鎖。無法獲得後就直接退出了。
公平鎖
一般意義上的鎖是不公平的,不一定先來的執行緒能先得到鎖,後來的執行緒就後得到鎖。不公平的鎖可能會產生飢餓現象。
公平鎖的意思就是,這個鎖能保證執行緒是先來的先得到鎖。雖然公平鎖不會產生飢餓現象,但是公平鎖的效能會比非公平鎖差很多。
使用方法:
public ReentrantLock(boolean fair)
public static ReentrantLock fairLock = new ReentrantLock(true);
相關文章
- ReentrantLock 使用ReentrantLock
- Java多執行緒11:ReentrantLock的使用和ConditionJava執行緒ReentrantLock
- Java中的ReentrantLock鎖JavaReentrantLock
- ReentrantLock & AQSReentrantLockAQS
- ReentrantLock類ReentrantLock
- synchronized與ReentrantLock的區別synchronizedReentrantLock
- Synchronized 與 ReentrantLock 的區別synchronizedReentrantLock
- ReentrantLock的條件佇列ReentrantLock佇列
- 分析ReentrantLock的實現原理ReentrantLock
- ReentrantLock原理分析ReentrantLock
- 淺析 ReentrantLockReentrantLock
- ReentrantLock原始碼ReentrantLock原始碼
- ReentrantLock詳解ReentrantLock
- 美團後臺篇中的ReentrantLockReentrantLock
- 簡單聊聊Java中的ReentrantLockJavaReentrantLock
- Java synchronized與ReentrantLock的區別JavasynchronizedReentrantLock
- ReentrantLock原始碼解析ReentrantLock原始碼
- 死磕Java——ReentrantLockJavaReentrantLock
- 深入理解 ReentrantLockReentrantLock
- ReentrantLock實現原理ReentrantLock
- Java併發——ReentrantLockJavaReentrantLock
- ReentrantLock原始碼分析ReentrantLock原始碼
- Java JUC ReentrantLock解析JavaReentrantLock
- ReentrantLock 實現原理ReentrantLock
- 徹底理解ReentrantLockReentrantLock
- [Java併發]ReentrantLockJavaReentrantLock
- 【Java】深入理解ReentrantLock可重入鎖之簡單使用JavaReentrantLock
- 比synchronized效能更好,功能更多的ReentrantLocksynchronizedReentrantLock
- 深入理解ReentrantLock的實現原理ReentrantLock
- 理解J.U.C中的ReentrantLockReentrantLock
- 不得不知的ReentrantLock原始碼ReentrantLock原始碼
- 【Interview】深入理解ReentrantLockViewReentrantLock
- Java鎖之ReentrantLock(一)JavaReentrantLock
- Java鎖之ReentrantLock(二)JavaReentrantLock
- ReentrantLock原始碼解讀ReentrantLock原始碼
- Synchronize和ReentrantLock區別ReentrantLock
- 06 ReentrantLock之ConditionReentrantLock
- 面試中如何答好:ReentrantLock面試ReentrantLock