多線程之LockSupper線程阻塞工具類

LockSupper介紹:

所有的方法都是靜態方法,可以讓線程在任意位置阻塞,當然阻塞之後肯定得有喚醒的方法。

源碼LockSupper不能被實例化(構造函數是私有的)

 

源碼解釋參考:

https://blog.csdn.net/secsf/article/details/78560013

 

主要有兩類方法park unpark

爲什麼叫park呢,park英文意思爲停車。我們如果把Thread看成一輛車的話,park就是讓車停下,unpark就是讓車啓動然後跑起來。

調用了park方法後當前線程被阻塞,必須由unpark方法喚醒,不然會一直阻塞

 

park可以帶參數

源碼:

* <p>This method does <em>not</em> report which of these caused the
     * method to return. Callers should re-check the conditions which caused
     * the thread to park in the first place. Callers may also determine,
     * for example, the interrupt status of the thread upon return.
     *
     * @param blocker the synchronization object responsible for this
     *        thread parking
     * @since 1.6
     */
    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, 0L);
        setBlocker(t, null);
    }
park()裏面傳遞一個對象,可以通過調用getBlocker()來獲得,
不過只有在線程已經堵塞的時候纔會獲得這個對象,當線程不再堵塞的時候
將無法在或的這個對象。你想一下就會明白,因爲許可只有一次,
當你第一次堵塞的時候傳遞了一個對象,當獲得許可之前你都可以獲得這個對象,
但是如果一旦這個線程獲得了許可,就不可以在獲得這個對象了。
假如有一輛載滿香豬的貨車過紅綠燈,當紅燈堵塞的時候,
所有的人都可以看到貨車裏面載的是香豬,但是當綠燈了,
貨車獲得許可,所有的人都無法知道貨車下次再經過的時候會帶什麼貨,
有些牽強,但希望幫助理解一下。

 

 

栗子代碼:

package com.demo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * @Description
 * @Author by mocar小師兄
 * @Date 2020/3/13 14:43
 **/
public class LockSupportDemo {
    private static Object object=new Object();

    private static class ThreadTask implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "\t 開始");
            synchronized (object){
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t 獲得鎖");
                LockSupport.park();
                if (Thread.currentThread().isInterrupted()){
                    System.out.println(Thread.currentThread().getName() + "\t 被中斷");
                }
                System.out.println(Thread.currentThread().getName() + "\t 執行任務完成");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new ThreadTask());
        Thread thread2 = new Thread(new ThreadTask());
        System.out.println("Main主線程開始");
        thread1.start();
        thread2.start();
        thread1.join(2000);
        thread2.join(2000);
        System.out.println("Main主線程結束");


    }
}

結果顯示:

當調用了part方法後,線程被阻塞,線程調用join方法也無法繼續執行,會繼續被阻塞

 

 

正確用法:

package com.demo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * @Description
 * @Author by mocar小師兄
 * @Date 2020/3/13 14:43
 **/
public class LockSupportDemo {
    private static Object object=new Object();

    private static class ThreadTask implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "\t 開始");
            synchronized (object){
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t 獲得鎖");
                if (Thread.currentThread().isInterrupted()){
                    System.out.println(Thread.currentThread().getName() + "\t 被中斷");
                }
                LockSupport.park();

                System.out.println(Thread.currentThread().getName() + "\t 執行任務完成");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new ThreadTask());
        Thread thread2 = new Thread(new ThreadTask());
        System.out.println("Main主線程開始");
        thread1.start();
        thread2.start();
        System.out.println("兩個子線程已開啓,Main主線程等待兩秒");
        TimeUnit.SECONDS.sleep(2);
        LockSupport.unpark(thread1);
        LockSupport.unpark(thread2);
        thread1.interrupt();//中斷thread1,看中斷後是否會釋放鎖,即thread2是否能獲取鎖
        /*thread1.join(2000);
        thread2.join(2000);*/
        System.out.println("Main主線程結束");


    }
}

 

 

 

 

順序問題:

LockSupport.park()和LockSupport.unpark(thread1)執行順序先後沒有那麼嚴格,
即使Main主線先執行了LockSupport.unpark(thread1)語句,
才進入的子線程執行LockSupport.park(),子線程也會獲得許可執行part後面的代碼。

 

 

參考:

https://www.jianshu.com/p/f1f2cd289205

 

 

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