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();
}
}