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

 

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