1. 程式人生 > >實戰Java高併發程式設計之LockSupport

實戰Java高併發程式設計之LockSupport

LockSupport簡介:

LockSupport是一個非常方便實用的執行緒阻塞工具,它可以線上程任意位置讓執行緒阻塞.和Thread.suspend()相比,它彌補了由於resume()在前發生,導致執行緒無法繼續執行的情況.和Object.wait()相比,它不需要先獲得物件的鎖,也不會丟擲中斷異常.

LockSupport是用於建立鎖和其他同步類的基本執行緒阻塞原語.

LockSupport是通過Unsafe類來實現的.

Unsafe的主要方法:

	/***
	 * 釋放由park方法建立的鎖
	 * 此方法也用於終止之前的park引起的阻塞
	 * 這個操作是不安全的,因為執行緒必須保證是活的 
	 * @param thread
	 *            解鎖的執行緒
	 */
	public native void unpark(Thread thread);

	/**
	 * 阻止執行緒,直到匹配的unpark發生,執行緒中斷或可選超時到期
	 * @param isAbsolute	是否是相對時間
	 * @param time		為0表示不設定超時
	 */
	public native void park(boolean isAbsolute, long time);
先來解析下兩個函式是做什麼的。
unpark函式為執行緒提供“許可(permit)”,執行緒呼叫park函式則等待“許可”。這個有點像訊號量,但是這個“許可”是不能疊加的,“許可”是一次性的。
比如執行緒B連續呼叫了三次unpark函式,當執行緒A呼叫park函式就使用掉這個“許可”,如果執行緒A再次呼叫park,則進入等待狀態。
注意,unpark函式可以先於park呼叫。比如執行緒B呼叫unpark函式,給執行緒A發了一個“許可”,那麼當執行緒A呼叫park時,它發現已經有“許可”了,那麼它會馬上再繼續執行。
實際上,park函式即使沒有“許可”,有時也會無理由地返回.

park和unpark的靈活之處
上面已經提到,unpark函式可以先於park呼叫,這個正是它們的靈活之處。
一個執行緒它有可能在別的執行緒unPark之前,或者之後,或者同時呼叫了park,那麼因為park的特性,它可以不用擔心自己的park的時序問題,否則,如果park必須要在unpark之前,那麼給程式設計帶來很大的麻煩!!
考慮一下,兩個執行緒同步,要如何處理?
在Java5裡是用wait/notify/notifyAll來同步的。wait/notify機制有個很蛋疼的地方是,比如執行緒B要用notify通知執行緒A,那麼執行緒B要確保執行緒A已經在wait呼叫上等待了,否則執行緒A可能永遠都在等待。程式設計的時候就會很蛋疼。
另外,是呼叫notify,還是notifyAll?
notify只會喚醒一個執行緒,如果錯誤地有兩個執行緒在同一個物件上wait等待,那麼又悲劇了。為了安全起見,貌似只能呼叫notifyAll了。
park/unpark模型真正解耦了執行緒之間的同步,執行緒之間不再需要一個Object或者其它變數來儲存狀態,不再需要關心對方的狀態.(摘自

點選開啟連結)

下面來看看LockSupport的原始碼:

	private LockSupport() {
	} // 無法例項化。

	private static void setBlocker(Thread t, Object arg) {
		// 即使是volatile, hotspot虛擬節機也不需要在此設定屏障
		UNSAFE.putObject(t, parkBlockerOffset, arg);
	}

	/**
	 * 如果給定的執行緒許可不可用的時候呼叫此方法將變成可用. 如果執行緒在park上被阻塞,那麼它將被解除阻塞
	 * 否則,它的下一次呼叫park保證不被阻塞
	 * 如果給定的執行緒尚未啟動,則此操作根本無法保證任何效果
	 * 
	 * @param 將執行緒執行緒解除標記,或{@code null},在這種情況下,此操作不起作用
	 */
	public static void unpark(Thread thread) {
		if (thread != null)
			UNSAFE.unpark(thread);
	}

	/**
	 * 禁用當前執行緒進行執行緒排程,除非許可證可用 如果許可可用,則它被消耗,並且該呼叫立即返回
	 * 否則當前執行緒將被禁用以進行執行緒排程,並且處於休眠狀態,直至發生三件事情之一
	 *
	 * 1.一些其他執行緒呼叫當前執行緒作為目標unpark
	 * 2.一些其他執行緒中斷當前執行緒
	 * 3.不合邏輯呼叫的返回
	 * 此方法不報告其中哪一個導致返回的方法 
	 * 呼叫者應重新檢查導致執行緒首先park的條件。 呼叫者也可以確定, 例如,執行緒在返回時的中斷狀態
	 * 
	 * @param 阻止同步物件負責此執行緒park
	 */
	public static void park(Object blocker) {
		Thread t = Thread.currentThread();
		setBlocker(t, blocker);
		UNSAFE.park(false, 0L);
		setBlocker(t, null);
	}

	/**
	 * 同上 增加等待時間
	 */
	public static void parkNanos(Object blocker, long nanos) {
		if (nanos > 0) {
			Thread t = Thread.currentThread();
			setBlocker(t, blocker);
			UNSAFE.park(false, nanos);
			setBlocker(t, null);
		}
	}

	/**
	 * 禁用當前執行緒進行執行緒排程,直到指定的截止日期,除非許可可用
	 */
	public static void parkUntil(Object blocker, long deadline) {
		Thread t = Thread.currentThread();
		setBlocker(t, blocker);
		UNSAFE.park(true, deadline);
		setBlocker(t, null);
	}

	/**
	 * 返回提供給最新一次呼叫尚未解除阻塞的park方法blocker物件,如果不阻塞則返回null 
	 */
	public static Object getBlocker(Thread t) {
		if (t == null)
			throw new NullPointerException();
		return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
	}

	/**
	 * 禁用當前執行緒進行執行緒排程,除非許可證可用
	 */
	public static void park() {
		UNSAFE.park(false, 0L);
	}
demo:
public class LockSupportDemo {
	public static Object u = new Object();
	static ChangeObjectThread t1 = new ChangeObjectThread("t1");
	static ChangeObjectThread t2 = new ChangeObjectThread("t2");

	public static class ChangeObjectThread extends Thread {
		public ChangeObjectThread(String name){
			super.setName(name);
		}
		@Override
		public void run() {
			synchronized (u) {
				System.out.println("in "+getName());
				LockSupport.park(this);
			}
		}
	}
	public static void main(String[] args) throws InterruptedException {
		t1.start();
		Thread.sleep(1000);
		t2.start();
		LockSupport.unpark(t1);
		LockSupport.unpark(t2);
		t1.join();
		t2.join();
	}
}



相關推薦

實戰Java併發程式設計LockSupport

LockSupport簡介: LockSupport是一個非常方便實用的執行緒阻塞工具,它可以線上程任意位置讓執行緒阻塞.和Thread.suspend()相比,它彌補了由於resume()在前發生,導致執行緒無法繼續執行的情況.和Object.wait()相比,它不需要先

實戰java併發程式設計CountDownLatch原始碼分析

首先看第一個! CountDownLatch 使用場景 CountDownLatch類是常見的併發同步控制類,適用於某一執行緒的執行在其他多個執行緒執行完成之後,比如火箭發射前需要各項指標檢查,只有當各項指標檢查完才能發射,再比如解析多個excel文件,只有當

實戰java併發程式設計ReentrantReadWriteLoc原始碼分析

前面分析了併發工具類CountDownLatch和CyclicBarrier,本文分享分析比較重要的ReentrantReadWriteLock。 使用場景 以前的同步方式需要對讀、寫操作進行同步,讀讀之間,讀寫之間,寫寫之間等;工程師們發現讀讀之間並不會影響資

實戰Java併發程式設計Java記憶體模型和執行緒安全

Java記憶體模型 原子性: 是指一個操作是不可中斷的.即使多個執行緒一起執行的時候,一個操作一旦開始,就不會被其他執行緒干擾. 一般CPU的指令是原子的. Q:i++是原子操作嗎? A:不是.

實戰Java併發程式設計.epub

    【下載地址】 在過去單核CPU時代,單任務在一個時間點只能執行單一程式,隨著多核CPU的發展,並行程式開發就顯得尤為重要。 《實戰Java高併發程式設計》主要介紹基於Java的並行程式設計基礎、思路、方法和實戰。第一,立足於併發程式基礎,詳細介紹Ja

2018最新實戰Java併發程式設計

在過去單核CPU時代,單任務在一個時間點只能執行單一程式,隨著多核CPU的發展,並行程式開發就顯得尤為重要。《實戰Java高併發程式設計》主要介紹基於Java的並行程式設計基礎、思路、方法和實戰。第一,立足於併發程式基礎,詳細介紹Java中進行並行程式設計的基本方法。第二,進一步詳細介紹JDK中對並

Java併發程式設計synchronized關鍵字(二)

上一篇文章講了synchronized的部分關鍵要點,詳見:Java高併發程式設計之synchronized關鍵字(一) 本篇文章接著講synchronized的其他關鍵點。 在使用synchronized關鍵字的時候,不要以字串常量作為鎖定物件。看下面的例子: public class

Java併發程式設計synchronized關鍵字(一)

首先看一段簡單的程式碼: public class T001 { private int count = 0; private Object o = new Object(); public void m() { //任何執行緒要執行下面這段程式碼

實戰Java併發程式設計(五、並行模式與演算法)

5.1單例模式 單例模式:是一種常用的軟體設計模式,在它的核心結構中值包含一個被稱為單例的特殊類。一個類只有一個例項,即一個類只有一個物件例項。  對於系統中的某些類來說,只有一個例項很重要,例如,一個系統中可以存在多個列印任務,但是隻能有一個正在工作的任務;售票時,一共有100張票,可有有

實戰Java併發程式設計(四、鎖的優化及注意事項)

在多核時代,使用多執行緒可以明顯地提升系統的效能。但事實上,使用多執行緒會額外增加系統的開銷。對於單任務或單執行緒的應用來說,其主要資源消耗在任務本身。對於多執行緒來說,系統除了處理功能需求外,還需要維護多執行緒環境特有的資訊,如執行緒本身的元資料,執行緒的排程,執行緒上下文的切換等。 4.1有

實戰Java併發程式設計(3.2 執行緒池)

1.Executor jdk提供了一套Executor框架,本質上是一個執行緒池。 newFixedThreadPool()方法:該方法返回一個固定數量的執行緒池。該執行緒池中的執行緒數量始終不變,當有一個新任務提交時,執行緒池中若有空閒執行緒,則立即執行,若沒有,則任務會暫存在一個任

實戰Java併發程式設計(3.1同步控制)

3.1重入鎖 重入鎖使用java.util.concurrent.locks.ReentrantLock來實現 public class Test implements Runnable { public static ReentrantLock lock = new Reentr

實戰Java併發程式設計》學習總結(3)

第6章  java8與併發 1 顯式函式指函式與外界交換資料的唯一渠道就是引數和返回值,顯式函式不會去讀取或者修改函式的外部狀態。這樣的函式對於除錯和排錯是有益的。 2 函數語言程式設計式申明式的程式設計方式。而命令式則喜歡大量使用可變物件和指令。如下 // 指令式程式設計 p

實戰Java併發程式設計》學習總結(2)

第3章  JDK併發包 1 synchronized的功能擴充套件:重入鎖。使用java.util.concurrent.locks.ReentrantLock類來實現。 import java.util.concurrent.locks.ReentrantLock; publi

實戰Java併發程式設計》學習總結(1)

第1章 走入並行世界 1 併發(Concurrency)和並行(Parallelism)都可以表示兩個或多個任務一起執行。但併發偏重於多個任務交替執行,而多個任務之間有可能還是序列。並行是真正意義上的“同時執行”。 2 有關並行的兩個重要定律。Amdahl定律強調當序列比例一定時,加速比是有

頂級架構師學習——第二階段:實戰Java併發程式設計

1、什麼是並行? 並行處理(ParallelProcessing)是計算機系統中能同時執行兩個或更多個處理機的一種計算方法。處理機可同時工作於同一程式的不同方面。並行處理的主要目的是節省大型和複雜問題的解決時間。 2、為什麼需要並行? 平行計算只有在  影象處理  和 

Java併發程式設計第一階段,多執行緒基礎深入淺出

汪文君高併發程式設計第一階段01講-課程大綱及主要內容介紹 汪文君高併發程式設計第一階段02講-簡單介紹什麼是執行緒 汪文君高併發程式設計第一階段03講-建立並啟動執行緒 汪文君高併發程式設計第一階段04講-執行緒生命週期以及start方法原始碼剖析 汪文君高併發程式設計第

實戰java併發程式設計 原始碼 source code

@rover這個是C++模板 --胡滿超 stack<Postion> path__;這個裡面 ”<> “符號是什麼意思?我在C++語言裡面沒見過呢? 初學者,大神勿噴。

實戰Java併發程式設計》讀後感

寫在前面無關的內容        白駒過隙,看下日曆已經畢業4年多,加上在大學裡的4年,算算在計算機界也躺了八年,按照格拉德韋爾的1萬小時定律差不多我也該成為行業的專家了,然後並沒有。當看著“什麼是Java?”、“什麼是程式?”、“多執行緒是什麼?”、“怎麼構建一個合理的大型

實戰Java併發程式設計(一)走進併發世界

阻塞(blocking)一個執行緒是阻塞的,那麼其它的執行緒釋放資源之前,當前執行緒無法繼續執行。使用synchronized或者重入鎖會使執行緒這是。 無飢餓(starvation-free):對於非公平的鎖來說,系統允許高優先順序的執行緒插隊,會造成飢餓;而公平的鎖則不會造成飢餓。 無障礙(obstruc