ReentrantLock 爲synchronized替代品,JDK1.5之前,jvm沒對synchronized過多優化時
ReentrantLock 性能遠遠大於synchronized。
可重入:一個線程對自己來說,是可以重複進入一個鎖的,不然自己就把自己卡死了。
可中斷:調用lockInterruptibly()方法,即設置該鎖可中斷。
可限時:tryLock方法可以限時多久獲取鎖,獲取不到就可以不等了,做別的事(如釋放掉自己持有的其他鎖)。
公平鎖:public ReentrantLock(boolean fair)有參構造方法(默認無參構造方法爲非公平的),即可設定是否爲公平鎖(先來先獲取,後來後獲取)
雖然公平但是性能要低一些,因爲排序浪費了性能。
由於它是線程安全的下屬代碼結果永遠爲
2000000
import java.util.concurrent.locks.ReentrantLock;
/**
* @Author:minglu
* @Description:
* @Date: 2018/11/26
*/
public class ReenterLock implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0;
@Override
public void run() {
for (int j = 0; j <1000000 ; j++) {
lock.lock();
//lock.lock();
try{
i++;
}finally {
lock.unlock();
//lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
ReenterLock t1 = new ReenterLock();
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t1);
thread1.start();thread2.start();
thread1.join();thread2.join();
System.out.println(i);
}
}
注意,是可以多次加鎖的(可重用),但是加了多少次,最後得釋放多少次如果上述代碼改成兩個lock,一次unlock。
則運行看不到輸出結果。
執行jps找到當前進程id8372
執行jstack 8372,可以看到,線程1處於watting狀態。
C:\Users\Administrator>jps
8372 ReenterLock
3784
4312 Jps
8328 Launcher
C:\Users\Administrator>jstack 8372
2018-11-26 21:49:05
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode):
"Thread-1" #12 prio=5 os_prio=0 tid=0x00000000187a3000 nid=0x216c waiting on con
dition [0x000000001998e000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000d61a0140> (a java.util.concurrent.lock
s.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInt
errupt(AbstractQueuedSynchronizer.java:836)
可中斷demo
import java.util.concurrent.locks.ReentrantLock;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
/**
* @Author:minglu
* @Description:
* @Date: 2018/11/26
*/
public class ReenterLock2 implements Runnable {
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock = 0;
public ReenterLock2(int lock) {
this.lock = lock;
}
@Override
public void run() {
try{
if (lock == 1){
lock1.lockInterruptibly();
try{
Thread.sleep(500);
}catch(InterruptedException e){}
lock2.lockInterruptibly();
}else{
lock2.lockInterruptibly();
try{
Thread.sleep(500);
}catch(InterruptedException e){}
lock1.lockInterruptibly();
}
}catch (InterruptedException e) {
e.printStackTrace();
} 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 {
ReenterLock2 t1 = new ReenterLock2(1);
ReenterLock2 t2 = new ReenterLock2(1);
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();thread2.start();
Thread.sleep(500);
DeadlockChecker.check();
}
/**
* 死鎖檢測靜態內部類DeadlockChecker
*/
static class DeadlockChecker
{
//Returns the managed bean for the thread system of the Java virtual machine
//拿到虛擬機線程系統
private final static ThreadMXBean mbean = ManagementFactory
.getThreadMXBean();
//匿名靜態內部類deadlockChecker
final static Runnable deadlockChecker = new Runnable()
{
@Override
public void run()
{
// TODO Auto-generated method stub
while (true)
{
//返回死鎖線程的id數組
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())
{
t.interrupt();
}
}
}
}
try
{
Thread.sleep(5000);
}
catch (Exception e)
{
// TODO: handle exception
}
}
}
};
public static void check()
{
Thread t = new Thread(deadlockChecker);
t.setDaemon(true);//設爲守護線程
t.start();
}
}
}
可限時demo
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Author:minglu
* @Description:
* @Date: 2018/11/26
*/
public class TimeLocker implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try{
if(lock.tryLock(5, TimeUnit.SECONDS)){//限時5秒拿鎖
Thread.sleep(6000);//6秒,則另一個只等5秒,拿不到
System.out.println("拿到鎖了,做自己的事");
}else{
System.out.println("沒拿到鎖,一般要做的事是釋放自己拿到的鎖,避免別人一直等");
}
}catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(lock.isHeldByCurrentThread()){//查詢當前線程是否持有該鎖
lock.unlock();
}
}
}
public static void main(String[] args) {
TimeLocker locker = new TimeLocker();
Thread t1 = new Thread(locker);
Thread t2 = new Thread(locker);
t1.start();
t2.start();
}
}