ReentrantLock 重入锁

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章