成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

LockSupport:一個很靈活的線程工具類

開發(fā) 開發(fā)工具
LockSupport是一個編程工具類,主要是為了阻塞和喚醒線程用的。使用它我們可以實現(xiàn)很多功能,今天主要就是對這個工具類的講解,希望對你有幫助。

[[356199]]

LockSupport是一個編程工具類,主要是為了阻塞和喚醒線程用的。使用它我們可以實現(xiàn)很多功能,今天主要就是對這個工具類的講解,希望對你有幫助:

一、LockSupport簡介

1、LockSupport是什么

剛剛開頭提到過,LockSupport是一個線程工具類,所有的方法都是靜態(tài)方法,可以讓線程在任意位置阻塞,也可以在任意位置喚醒。

它的內(nèi)部其實兩類主要的方法:park(停車阻塞線程)和unpark(啟動喚醒線程)。

  1. //(1)阻塞當(dāng)前線程 
  2. public static void park(Object blocker);  
  3. //(2)暫停當(dāng)前線程,有超時時間 
  4. public static void parkNanos(Object blocker, long nanos);  
  5. //(3)暫停當(dāng)前線程,直到某個時間 
  6. public static void parkUntil(Object blocker, long deadline);  
  7. //(4)無期限暫停當(dāng)前線程 
  8. public static void park();  
  9. //(5)暫停當(dāng)前線程,不過有超時時間的限制 
  10. public static void parkNanos(long nanos);  
  11. //(6)暫停當(dāng)前線程,直到某個時間 
  12. public static void parkUntil(long deadline);   
  13. //(7)恢復(fù)當(dāng)前線程 
  14. public static void unpark(Thread thread);  
  15. public static Object getBlocker(Thread t); 

注意上面的123方法,都有一個blocker,這個blocker是用來記錄線程被阻塞時被誰阻塞的。用于線程監(jiān)控和分析工具來定位原因的。

現(xiàn)在我們知道了LockSupport是用來阻塞和喚醒線程的,而且之前相信我們都知道wait/notify也是用來阻塞和喚醒線程的,那和它相比,LockSupport有什么優(yōu)點呢?

2、與wait/notify對比

這里假設(shè)你已經(jīng)了解了wait/notify的機制,如果不了解,可以在網(wǎng)上一搜,很簡單。相信你既然學(xué)到了這個LockSupport,相信你已經(jīng)提前已經(jīng)學(xué)了wait/notify。

我們先來舉一個使用案例:

  1. public class LockSupportTest { 
  2.     public static class MyThread extends Thread { 
  3.         @Override 
  4.         public void run() { 
  5.             System.out.println(getName() + " 進入線程"); 
  6.             LockSupport.park(); 
  7.             System.out.println("t1線程運行結(jié)束"); 
  8.         } 
  9.     } 
  10.     public static void main(String[] args) { 
  11.         MyThread t1 = new MyThread(); 
  12.         t1.start(); 
  13.         System.out.println("t1已經(jīng)啟動,但是在內(nèi)部進行了park"); 
  14.         LockSupport.unpark(t1); 
  15.         System.out.println("LockSupport進行了unpark"); 
  16.     } 

上面這段代碼的意思是,我們定義一個線程,但是在內(nèi)部進行了park,因此需要unpark才能喚醒繼續(xù)執(zhí)行,不過上面,我們在MyThread進行的park,在main線程進行的unpark。

這樣來看,好像和wait/notify沒有什么區(qū)別。那他的區(qū)別到底是什么呢?這個就需要仔細的觀察了。這里主要有兩點:

(1)wait和notify都是Object中的方法,在調(diào)用這兩個方法前必須先獲得鎖對象,但是park不需要獲取某個對象的鎖就可以鎖住線程。

(2)notify只能隨機選擇一個線程喚醒,無法喚醒指定的線程,unpark卻可以喚醒一個指定的線程。

區(qū)別就是這倆,還是主要從park和unpark的角度來解釋的。既然這個LockSupport這么強,我們就深入一下他的源碼看看。

二、源碼分析(基于jdk1.8)

1、park方法

  1. public static void park(Object blocker) { 
  2.         Thread t = Thread.currentThread(); 
  3.         setBlocker(t, blocker); 
  4.         UNSAFE.park(false, 0L); 
  5.         setBlocker(t, null); 
  6.     } 

blocker是用來記錄線程被阻塞時被誰阻塞的。用于線程監(jiān)控和分析工具來定位原因的。setBlocker(t, blocker)方法的作用是記錄t線程是被broker阻塞的。因此我們只關(guān)注最核心的方法,也就是UNSAFE.park(false, 0L)。

UNSAFE是一個非常強大的類,他的的操作是基于底層的,也就是可以直接操作內(nèi)存,因此我們從JVM的角度來分析一下:

每個java線程都有一個Parker實例:

  1. class Parker : public os::PlatformParker { 
  2. private: 
  3.   volatile int _counter ; 
  4.   ... 
  5. public
  6.   void park(bool isAbsolute, jlong time); 
  7.   void unpark(); 
  8.   ... 
  9. class PlatformParker : public CHeapObj<mtInternal> { 
  10.   protected: 
  11.     pthread_mutex_t _mutex [1] ; 
  12.     pthread_cond_t  _cond  [1] ; 
  13.     ... 

我們換一種角度來理解一下park和unpark,可以想一下,unpark其實就相當(dāng)于一個許可,告訴特定線程你可以停車,特定線程想要park停車的時候一看到有許可,就可以立馬停車?yán)^續(xù)運行了。因此其執(zhí)行順序可以顛倒。

現(xiàn)在有了這個概念,我們體會一下上面JVM層面park的方法,這里面counter字段,就是用來記錄所謂的“許可”的。

本小部分總結(jié)來源于:https://www.jianshu.com/p/1f16b838ccd8

當(dāng)調(diào)用park時,先嘗試直接能否直接拿到“許可”,即_counter>0時,如果成功,則把_counter設(shè)置為0,并返回。

  1. void Parker::park(bool isAbsolute, jlong time) { 
  2.   // Ideally we'd do something useful while spinning, such 
  3.   // as calling unpackTime(). 
  4.   // Optional fast-path check
  5.   // Return immediately if a permit is available. 
  6.   // We depend on Atomic::xchg() having full barrier semantics 
  7.   // since we are doing a lock-free update to _counter. 
  8.   if (Atomic::xchg(0, &_counter) > 0) return

如果不成功,則構(gòu)造一個ThreadBlockInVM,然后檢查_counter是不是>0,如果是,則把_counter設(shè)置為0,unlock mutex并返回:

  1. ThreadBlockInVM tbivm(jt); 
  2.  // no wait needed 
  3.  if (_counter > 0)  {  
  4.    _counter = 0; 
  5.    status = pthread_mutex_unlock(_mutex); 

否則,再判斷等待的時間,然后再調(diào)用pthread_cond_wait函數(shù)等待,如果等待返回,則把_counter設(shè)置為0,unlock mutex并返回:

  1. if (time == 0) {   
  2.   status = pthread_cond_wait (_cond, _mutex) ;   
  3. }   
  4. _counter = 0 ;   
  5. status = pthread_mutex_unlock(_mutex) ;   
  6. assert_status(status == 0, status, "invariant") ;   
  7. OrderAccess::fence();  

這就是整個park的過程,總結(jié)來說就是消耗“許可”的過程。

2、unpark

還是先來看一下JDK源碼:

  1. /** 
  2.     * Makes available the permit for the given thread, if it 
  3.     * was not already available.  If the thread was blocked on 
  4.     * {@code park} then it will unblock.  Otherwise, its next call 
  5.     * to {@code park} is guaranteed not to block. This operation 
  6.     * is not guaranteed to have any effect at all if the given 
  7.     * thread has not been started. 
  8.     * 
  9.     * @param thread the thread to unpark, or {@code null}, in which case 
  10.     *        this operation has no effect 
  11.     */ 
  12.    public static void unpark(Thread thread) { 
  13.        if (thread != null
  14.            UNSAFE.unpark(thread); 
  15.    } 

上面注釋的意思是給線程生產(chǎn)許可證。

當(dāng)unpark時,則簡單多了,直接設(shè)置_counter為1,再unlock mutext返回。如果_counter之前的值是0,則還要調(diào)用pthread_cond_signal喚醒在park中等待的線程:

  1. void Parker::unpark() {   
  2.   int s, status ;   
  3.   status = pthread_mutex_lock(_mutex);   
  4.   assert (status == 0, "invariant") ;   
  5.   s = _counter;   
  6.   _counter = 1;   
  7.   if (s < 1) {   
  8.      if (WorkAroundNPTLTimedWaitHang) {   
  9.         status = pthread_cond_signal (_cond) ;   
  10.         assert (status == 0, "invariant") ;   
  11.         status = pthread_mutex_unlock(_mutex);   
  12.         assert (status == 0, "invariant") ;   
  13.      } else {   
  14.         status = pthread_mutex_unlock(_mutex);   
  15.         assert (status == 0, "invariant") ;   
  16.         status = pthread_cond_signal (_cond) ;   
  17.         assert (status == 0, "invariant") ;   
  18.      }   
  19.   } else {   
  20.     pthread_mutex_unlock(_mutex);   
  21.     assert (status == 0, "invariant") ;   
  22.   }   
  23. }   

ok,現(xiàn)在我們已經(jīng)對源碼進行了分析,整個過程其實就是生產(chǎn)許可和消費許可的過程。而且這個生產(chǎn)過程可以反過來。也就是先生產(chǎn)再消費。下面我們使用幾個例子驗證一波。

三、LockSupport使用

1、先interrupt再park

  1. public class LockSupportTest { 
  2.     public static class MyThread extends Thread { 
  3.         @Override 
  4.         public void run() { 
  5.             System.out.println(getName() + " 進入線程"); 
  6.             LockSupport.park(); 
  7.             System.out.println(" 運行結(jié)束"); 
  8.             System.out.println("是否中斷:" + Thread.currentThread().isInterrupted()); 
  9.         } 
  10.     } 
  11.     public static void main(String[] args) { 
  12.         MyThread t1 = new MyThread(); 
  13.         t1.start(); 
  14.         System.out.println("t1線程已經(jīng)啟動了,但是在內(nèi)部LockSupport進行了park"); 
  15.         t1.interrupt(); 
  16.         System.out.println("main線程結(jié)束"); 
  17.     } 

我們看一下結(jié)果:

2、先unpark再park

  1. public static class MyThread extends Thread { 
  2.         @Override 
  3.         public void run() { 
  4.             try { 
  5.                 TimeUnit.SECONDS.sleep(1); 
  6.             } catch (InterruptedException e) { 
  7.                 e.printStackTrace(); 
  8.             } 
  9.             System.out.println(getName() + " 進入線程"); 
  10.             LockSupport.park(); 
  11.             System.out.println(" 運行結(jié)束"); 
  12.         } 
  13.     } 

我們只需在park之前先休眠1秒鐘,這樣可以確保unpark先執(zhí)行。

本文轉(zhuǎn)載自微信公眾號「愚公要移山」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系愚公要移山公眾號。

 

責(zé)任編輯:武曉燕 來源: 愚公要移山
相關(guān)推薦

2023-07-07 07:44:41

線程中斷LockSuppor

2025-04-29 10:28:25

2023-12-01 08:31:20

HTML解析庫

2023-08-01 07:25:38

Expresso框架API

2012-07-17 17:05:55

JavaScript

2023-11-03 11:57:04

2019-09-09 14:19:37

程序員離職員工

2021-02-04 11:11:08

開發(fā)技能工具

2021-02-04 11:46:49

GithubSQL工具Franchise

2011-03-24 09:34:41

SPRING

2021-11-04 17:23:03

Java對象 immutable

2021-08-11 07:53:22

Git rejecthint

2013-04-25 09:55:21

進程線程

2024-03-19 13:51:31

JavaScript插件

2021-11-15 10:35:46

Python線程代碼

2022-03-07 05:53:41

線程CPU代碼

2022-03-09 09:43:01

工具類線程項目

2024-12-19 08:58:50

2021-03-31 13:28:17

開源工具Python編程語言

2016-12-15 08:54:52

線程sessionopenSession
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 久久毛片 | 中文一区| 亚洲色图综合 | 337p日韩| 看片网站在线 | 91色在线| 国产盗摄视频 | 欧美精品一区二区三区四区 在线 | 男女污污动态图 | 精品国产乱码久久久久久闺蜜 | 欧美一级免费看 | 欧美一级淫片免费视频黄 | 男人天堂av网站 | 欧美亚洲激情 | 一区二区三区久久久 | 国产成人精品久久 | 国产性色视频 | 精品久久国产 | 欧美一级二级三级视频 | 亚洲免费在线 | 国产精品毛片一区二区在线看 | 亚洲精品在线免费观看视频 | 免费在线观看毛片 | 日韩免费看片 | 国产在线观看一区二区三区 | 精品av久久久久电影 | 欧美精品一区三区 | 日韩欧美精品一区 | 国产精品3区 | 亚洲日韩中文字幕一区 | 99综合网 | 亚洲国产一区二区在线 | 91最新入口 | 粉嫩一区二区三区性色av | 日韩中文字幕在线观看 | 夜夜干夜夜操 | 亚州一区二区三区 | 亚洲一区二区三区四区五区午夜 | 欧美性猛交一区二区三区精品 | 久久精品国产久精国产 | 午夜精品久久久久久久久久久久久 |