關於互斥鎖:javascript
所謂互斥鎖, 指的是一次最多隻能有一個線程持有的鎖. 在jdk1.5以前, 咱們一般使用synchronized機制控制多個線程對共享資源的訪問. 而如今, Lock提供了比synchronized機制更普遍的鎖定操做, Lock和synchronized機制的主要區別:html
synchronized機制提供了對與每一個對象相關的隱式監視器鎖的訪問, 並強制全部鎖獲取和釋放均要出如今一個塊結構中, 當獲取了多個鎖時, 它們必須以相反的順序釋放. synchronized機制對鎖的釋放是隱式的, 只要線程運行的代碼超出了synchronized語句塊範圍, 鎖就會被釋放. 而Lock機制必須顯式的調用Lock對象的unlock()方法才能釋放鎖, 這爲獲取鎖和釋放鎖不出如今同一個塊結構中, 以及以更自由的順序釋放鎖提供了可能. java
關於可重入: api
1、2.4.1 內部鎖多線程
Java 提供了原子性的內置鎖機制: sychronized 塊。它包含兩個部分:鎖對象的引用和這個鎖保護的代碼塊:app
synchronized(lock) {ide
// 訪問或修改被鎖保護的共享狀態性能
}單元測試
內部鎖扮演了互斥鎖( mutual exclusion lock, 也稱做 mutex )的角色,一個線程擁有鎖的時候,別的線程阻塞等待。測試
2.4.2 重進入(Reentrancy )
重入性:指的是同一個線程屢次試圖獲取它所佔有的鎖,請求會成功。當釋放鎖的時候,直到重入次數清零,鎖才釋放完畢。
Public class Widget {
Public synchronized void doSomething(){
…
}
}
Public class LoggingWidget extends Widget {
Public synchronized void doSomething(){
System.out.println(toString()+」:calling doSomething」);
Super.doSomething();
}
}
2、通常來講,在多線程程序中,某個任務在持有某對象的鎖後才能運行任務,其餘任務只有在該任務釋放同一對象鎖後才能擁有對象鎖,而後執行任務。因而,想到,同一個任務在持有同一個對象的鎖後,在不釋放鎖的狀況下,繼續調用同一個對象的其餘同步(synchronized)方法,該任務是否會再次持有該對象鎖呢?
答案是確定的。同一個任務在調用同一個對象上的其餘synchronized方法,能夠再次得到該對象鎖。
Java代碼

- synchronized m1(){
- //加入此時對鎖a的計數是N
- m2(); //進入m2的方法體以後鎖計數是N+1,離開m2後是N
- }
- synchronized m2(){}
同一任務和對象鎖的問題:http://www.iteye.com/topic/728485
Java代碼

- /*public class ReentrantLock
- extends Object implements Lock, Serializable
- */
一個可重入的互斥鎖 Lock,它具備與使用 synchronized 方法和語句所訪問的隱式監視器鎖相同的一些基本行爲和語義,但功能更強大。
ReentrantLock 將由最近成功得到鎖,而且尚未釋放該鎖的線程所擁有。當鎖沒有被另外一個線程所擁有時,調用 lock 的線程將成功獲取該鎖並返回。若是當前線程已經擁有該鎖,此方法將當即返回。可使用 isHeldByCurrentThread() 和 getHoldCount() 方法來檢查此狀況是否發生。
此類的構造方法接受一個可選的公平 參數。當設置爲 true 時,在多個線程的爭用下,這些鎖傾向於將訪問權授予等待時間最長的線程。不然此鎖將沒法保證任何特定訪問順序。與採用默認設置(使用不公平鎖)相比,使用公平鎖的程序在許多線程訪問時表現爲很低的整體吞吐量(即速度很慢,經常極其慢),可是在得到鎖和保證鎖分配的均衡性時差別較小。不過要注意的是,公平鎖不能保證線程調度的公平性。所以,使用公平鎖的衆多線程中的一員可能得到多倍的成功機會,這種狀況發生在其餘活動線程沒有被處理而且目前並未持有鎖時。還要注意的是,未定時的 tryLock 方法並無使用公平設置。由於即便其餘線程正在等待,只要該鎖是可用的,此方法就能夠得到成功。
JDK:http://www.xasxt.com/java/api/java/util/concurrent/locks/ReentrantLock.html
Java代碼

- /*構造方法摘要
- ReentrantLock()
- 建立一個 ReentrantLock 的實例。
- ReentrantLock(boolean fair)
- 建立一個具備給定公平策略的 ReentrantLock。
- */
Java代碼

- /**public void lock()
- 獲取鎖。
- 若是該鎖沒有被另外一個線程保持,則獲取該鎖並當即返回,將鎖的保持計數設置爲 1。
- 若是當前線程已經保持該鎖,則將保持計數加 1,而且該方法當即返回。
- 若是該鎖被另外一個線程保持,則出於線程調度的目的,禁用當前線程,而且在得到鎖以前,該線程將一直處於休眠狀態,此時鎖保持計數被設置爲 1。
- */
ReentrantLock 的lock機制有2種,忽略中斷鎖和響應中斷鎖,這給咱們帶來了很大的靈活性。好比:若是A、B 2個線程去競爭鎖,A線程獲得了鎖,B線程等待,可是A線程這個時候實在有太多事情要處理,就是 一直不返回,B線程可能就會等不及了,想中斷本身,再也不等待這個鎖了,轉而處理其餘事情。這個時候ReentrantLock就提供了2種機制,第一,B線程中斷本身(或者別的線程中斷它),可是ReentrantLock 不去響應,繼續讓B線程等待,你再怎麼中斷,我全當耳邊風(synchronized原語就是如此);第二,B線程中斷本身(或者別的線程中斷它),ReentrantLock 處理了這個中斷,而且再也不等待這個鎖的到來,徹底放棄。請看例子:
Example1:
Java代碼

- package test;
-
- public interface IBuffer {
- public void write();
- public void read() throws InterruptedException;
- }
使用Synchronized:
Java代碼

- package test;
-
- public class Buffer implements IBuffer {
-
- private Object lock;
-
- public Buffer() {
- lock = this;
- }
-
- public void write() {
- synchronized (lock) {
- long startTime = System.currentTimeMillis();
- System.out.println("開始往這個buff寫入數據…");
- for (;;)// 模擬要處理很長時間
- {
- if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
- break;
- }
- System.out.println("終於寫完了");
- }
- }
-
- public void read() {
- synchronized (lock) {
- System.out.println("從這個buff讀數據");
- }
- }
-
- }
使用ReentrantLock:
Java代碼

- package test;
- import java.util.concurrent.locks.ReentrantLock;
- public class BufferInterruptibly implements IBuffer {
-
- private ReentrantLock lock = new ReentrantLock();
-
- public void write() {
- lock.lock();
- try {
- long startTime = System.currentTimeMillis();
- System.out.println("開始往這個buff寫入數據…");
- for (;;)// 模擬要處理很長時間
- {
- if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
- break;
- }
- System.out.println("終於寫完了");
- } finally {
- lock.unlock();
- }
- }
-
- public void read() throws InterruptedException{
- lock.lockInterruptibly();// 注意這裏,能夠響應中斷
- try {
- System.out.println("從這個buff讀數據");
- } finally {
- lock.unlock();
- }
- }
-
- }
測試類(注意那兩個線程不是內部類!):
Java代碼

- package test;
-
- public class Test {
- //是用ReentrantLock,仍是用synchronized
- public static boolean useSynchronized = false;
- public static void main(String[] args) {
- IBuffer buff = null;
- if(useSynchronized){
- buff = new Buffer();
- }else{
- buff = new BufferInterruptibly();
- }
- final Writer writer = new Writer(buff);
- final Reader reader = new Reader(buff);
- writer.start();
- reader.start();
- new Thread(new Runnable() {
- public void run() {
- long start = System.currentTimeMillis();
- for (;;) {
- // 等5秒鐘去中斷讀
- if (System.currentTimeMillis() - start > 5000) {
- System.out.println("不等了,嘗試中斷");
- reader.interrupt();
- break;
- }
-
- }
-
- }
- }).start();
- }
- }
-
- class Writer extends Thread {
- private IBuffer buff;
-
- public Writer(IBuffer buff) {
- this.buff = buff;
- }
-
- @Override
- public void run() {
- buff.write();
- }
- }
-
- class Reader extends Thread {
- private IBuffer buff;
- public Reader(IBuffer buff) {
- this.buff = buff;
- }
- @Override
- public void run() {
- try {
- buff.read();
- } catch (InterruptedException e) {
- System.out.println("我不讀了");
- }
- System.out.println("讀結束");
- }
- }
結果:
使用ReentrantLock時:
開始往這個buff寫入數據…
不等了,嘗試中斷
我不讀了
讀結束
使用Synchronized時:
開始往這個buff寫入數據…
不等了,嘗試中斷
實例來源:http://blog.csdn.net/quqi99/article/details/5298017
實例2:
http://junlas.iteye.com/blog/846460
實例3:
http://www.blogjava.net/killme2008/archive/2007/09/14/145195.html
重要:
一個證實可中斷的例子:http://yanxuxin.iteye.com/blog/566713
關於多線程問題,signalAll,await問題:http://www.iteye.com/problems/72378
ReentrantLock :http://hujin.iteye.com/blog/479689
java的concurrent用法詳解:
http://www.open-open.com/bbs/view/1320131360999
ReentrantLock-互斥同步器:
http://www.cnblogs.com/mandela/archive/2011/04/08/2009810.html
一個重要Example:
Java代碼

- package tags;
-
- import java.util.Calendar;
-
- public class TestLock {
- private ReentrantLock lock = null;
-
- public int data = 100; // 用於線程同步訪問的共享數據
-
- public TestLock() {
- lock = new ReentrantLock(); // 建立一個自由競爭的可重入鎖
- }
- public ReentrantLock getLock() {
- return lock;
- }
-
- public void testReentry() {
- lock.lock();
- Calendar now = Calendar.getInstance();
- System.out.println(now.getTime() + " " + Thread.currentThread() + " get lock.");
- }
-
- public static void main(String[] args) {
- TestLock tester = new TestLock();
-
- //一、測試可重入
- tester.testReentry();
- tester.testReentry(); // 能執行到這裏而不阻塞,表示鎖可重入
- tester.testReentry(); // 再次重入
-
- // 釋放重入測試的鎖,要按重入的數量解鎖,不然其餘線程沒法獲取該鎖。
- tester.getLock().unlock();
- tester.getLock().unlock();
- tester.getLock().unlock();
-
- //二、測試互斥
- // 啓動3個線程測試在鎖保護下的共享數據data的訪問
- new Thread(new workerThread(tester)).start();
- new Thread(new workerThread(tester)).start();
- new Thread(new workerThread(tester)).start();
- }
-
-
- // 線程調用的方法
- public void testRun() throws Exception {
- lock.lock();
-
- Calendar now = Calendar.getInstance();
- try {
- // 獲取鎖後顯示 當前時間 當前調用線程 共享數據的值(並使共享數據 + 1)
- System.out.println(now.getTime() + " " + Thread.currentThread()+ " accesses the data " + data++);
- Thread.sleep(1000);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- }
- }
-
- // 工做線程,調用TestServer.testRun
- class workerThread implements Runnable {
-
- private TestLock tester = null;
-
- public workerThread(TestLock testLock) {
- this.tester = testLock;
- }
-
- public void run() {
- try {
- tester.testRun();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
Example3:
Java代碼

- package tags;
- import java.util.concurrent.locks.ReentrantLock;
-
- public class ReentrantLockSample {
-
- public static void main(String[] args) {
- testSynchronized();
- //testReentrantLock();
- }
-
- public static void testReentrantLock() {
- final SampleSupport1 support = new SampleSupport1();
- Thread first = new Thread(new Runnable() {
- public void run() {
- try {
- support.doSomething();
- }
- catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
-
- Thread second = new Thread(new Runnable() {
- public void run() {
- try {
- support.doSomething();
- }
- catch (InterruptedException e) {
- System.out.println("Second Thread Interrupted without executing counter++,beacuse it waits a long time.");
- }
- }
- });
-
- executeTest(first, second);
- }
-
- public static void testSynchronized() {
- final SampleSupport2 support2 = new SampleSupport2();
-
- Runnable runnable = new Runnable() {
- public void run() {
- support2.doSomething();
- }
- };
-
- Thread third = new Thread(runnable);
- Thread fourth = new Thread(runnable);
-
- executeTest(third, fourth);
- }
-
- /**
- * Make thread a run faster than thread b,
- * then thread b will be interruted after about 1s.
- * @param a
- * @param b
- */
- public static void executeTest(Thread a, Thread b) {
- a.start();
- try {
- Thread.sleep(100);
- b.start(); // The main thread sleep 100ms, and then start the second thread.
-
- Thread.sleep(1000);
- // 1s later, the main thread decided not to allow the second thread wait any longer.
- b.interrupt();
- }
- catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
-
- abstract class SampleSupport {
-
- protected int counter;
-
- /**
- * A simple countdown,it will stop after about 5s.
- */
- public void startTheCountdown() {
- long currentTime = System.currentTimeMillis();
- for (;;) {
- long diff = System.currentTimeMillis() - currentTime;
- if (diff > 5000) {
- break;
- }
- }
- }
- }
-
- class SampleSupport1 extends SampleSupport {
-
- private final ReentrantLock lock = new ReentrantLock();
-
- public void doSomething() throws InterruptedException {
- lock.lockInterruptibly(); // (1)
- System.out.println(Thread.currentThread().getName() + " will execute counter++.");
- startTheCountdown();
- try {
- counter++;
- }
- finally {
- lock.unlock();
- }
- }
- }
-
- class SampleSupport2 extends SampleSupport {
-
- public synchronized void doSomething() {
- System.out.println(Thread.currentThread().getName() + " will execute counter++.");
- startTheCountdown();
- counter++;
- }
- }
在這個例子中,輔助類SampleSupport提供一個倒計時的功能startTheCountdown(),這裏倒計時5s左右。SampleSupport1,SampleSupport2繼承其並分別的具備doSomething()方法,任何進入方法的線程會運行5s左右以後counter++而後離開方法釋放鎖。SampleSupport1是使用ReentrantLock機制,SampleSupport2是使用synchronized機制。
testSynchronized()和testReentrantLock()都分別開啓兩個線程執行測試方法executeTest(),這個方法會讓一個線程先啓動,另外一個過100ms左右啓動,而且隔1s左右試圖中斷後者。結果正如以前提到的第二點:interrupt()對於synchronized是沒有做用的,它依然會等待5s左右得到鎖執行counter++;而ReentrantLock機制能夠保證在線程還未得到而且試圖得到鎖時若是發現線程中斷,則拋出異常清除中斷標記退出競爭。因此testReentrantLock()中second線程不會繼續去競爭鎖,執行異常內的打印語句後線程運行結束。
來源:http://yanxuxin.iteye.com/blog/566713
Example4:
三個線程,線程名分別爲A、B、C,設計程序使得三個線程循環打印「ABC」10次後終止。如:ABCABCABCABCABCABCABCABCABCABC
Java代碼

- package tags;
-
- import java.util.concurrent.locks.ReentrantLock;
-
- public class ReentrantLockPractice {
-
- static ReentrantLock lock = new ReentrantLock();
- private static String[] threadArr = {"A","B","C"};
-
- public static void main(String[] args){
- ReentrantLockPractice pc = new ReentrantLockPractice();
- pc.startDemo();
- }
-
- void startDemo(){
- for(int i = 0;i<10;i++){
- for(String name : threadArr){
- TestThread t = new TestThread(name);
- t.start();
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
-
- class TestThread extends Thread{
-
- //自定義線程名字
- TestThread(String str){
- super(str);
- }
-
- public void run(){
- try {
- lock.lockInterruptibly();
- System.out.print(Thread.currentThread().getName());
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally{
- lock.unlock();
- }
- }
- }
-
- }
注意與Example2的區別,一個線材類定義在內部,一個在外部,注意區別。
其餘方法:
http://hxraid.iteye.com/blog/607228
相同:ReentrantLock提供了synchronized相似的功能和內存語義。
不一樣:
1.ReentrantLock功能性方面更全面,好比時間鎖等候,可中斷鎖等候,鎖投票等,所以更有擴展性。在多個條件變量和高度競爭鎖的地方,用ReentrantLock更合適,ReentrantLock還提供了Condition,對線程的等待和喚醒等操做更加靈活,一個ReentrantLock能夠有多個Condition實例,因此更有擴展性。
2.ReentrantLock必須在finally中釋放鎖,不然後果很嚴重,編碼角度來講使用synchronized更加簡單,不容易遺漏或者出錯。
3.ReentrantLock 的性能比synchronized會好點。
4.ReentrantLock提供了可輪詢的鎖請求,他能夠嘗試的去取得鎖,若是取得成功則繼續處理,取得不成功,能夠等下次運行的時候處理,因此不容易產生死鎖,而synchronized則一旦進入鎖請求要麼成功,要麼一直阻塞,因此更容易產生死鎖。
一、Lock的某些方法能夠決定多長時間內嘗試獲取鎖,若是獲取不到就拋異常,這樣就能夠必定程度上減輕死鎖的可能性。
若是鎖被另外一個線程佔據了,synchronized只會一直等待,很容易錯序死鎖
二、synchronized的話,鎖的範圍是整個方法或synchronized塊部分;而Lock由於是方法調用,能夠跨方法,靈活性更大
三、便於測試,單元測試時,能夠模擬Lock,肯定是否得到了鎖,而synchronized就沒辦法了
ReentrantLock比synchronized 強大在哪兒?
簡單說:
一、ReentrantLock能夠實現fair lock
public ReentrantLock(boolean fair) {
sync = (fair)? new FairSync() : new NonfairSync();
}
所謂fair lock就是看得到鎖的順序是否是和申請鎖的時間的順序是一致的
二、ReentrantLock支持中斷處理
public final void acquireInterruptibly(int arg) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
就是說那些持有鎖的線程一直不釋放,正在等待的線程能夠放棄等待。
三、ReentrantLock能夠和condition結合使用
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
內置鎖synchronized
顯式鎖Lock