ReentrantLock與synchronized都是爲了同步加鎖,但ReentrantLock相對效率比synchronized高,量級較輕。
synchronized在JDK1.5版本開始,嘗試優化。到JDK1.7版本後,優化效率已經很是好了。在絕對效率上,不比reentrantLock差多少。使用ReentrantLock,必須手工釋放鎖標記。通常都是在finally代碼塊中定義釋放鎖標記的unlock方法。ide
lock()與unlock()就像synchronized同步代碼塊的開始與結束,使用ReentrantLocky必定要記得unlock()解鎖優化
package com.bernardlowe.concurrent.t03; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Test_01 { Lock lock = new ReentrantLock(); void m1(){ try{ lock.lock(); // 加鎖 for(int i = 0; i < 10; i++){ TimeUnit.SECONDS.sleep(1); System.out.println("m1() method " + i); } }catch(InterruptedException e){ e.printStackTrace(); }finally{ lock.unlock(); // 解鎖 } } void m2(){ lock.lock(); System.out.println("m2() method"); lock.unlock(); } public static void main(String[] args) { final Test_01 t = new Test_01(); new Thread(new Runnable() { @Override public void run() { t.m1(); } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(new Runnable() { @Override public void run() { t.m2(); } }).start(); } }
嘗試鎖,顧名思義是嘗試獲取鎖標記trylock(),有兩種方式this
無參嘗試鎖:會根據是否能獲取當前鎖標記返回對應值操作系統
boolean tryLock();線程
有參阻塞嘗試鎖, 阻塞嘗試鎖,阻塞參數表明等待超時時間。3d
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;code
/** * 嘗試鎖 */ package com.bernardlowe.concurrent.t03; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Test_02 { Lock lock = new ReentrantLock(); void m1(){ try{ lock.lock(); for(int i = 0; i < 10; i++){ TimeUnit.SECONDS.sleep(1); System.out.println("m1() method " + i); } }catch(InterruptedException e){ e.printStackTrace(); }finally{ lock.unlock(); } } void m2(){ boolean isLocked = false; try{ // 嘗試鎖, 若是有鎖,沒法獲取鎖標記,返回false。 // 若是獲取鎖標記,返回true // isLocked = lock.tryLock(); // 阻塞嘗試鎖,阻塞參數表明的時長,嘗試獲取鎖標記。 // 若是超時,不等待。直接返回。 isLocked = lock.tryLock(5, TimeUnit.SECONDS); if(isLocked){ System.out.println("m2() method synchronized"); }else{ System.out.println("m2() method unsynchronized"); } }catch(Exception e){ e.printStackTrace(); }finally{ if(isLocked){ // 嘗試鎖在解除鎖標記的時候,必定要判斷是否獲取到鎖標記。 // 若是當前線程沒有獲取到鎖標記,會拋出異常。 lock.unlock(); } } } public static void main(String[] args) { final Test_02 t = new Test_02(); new Thread(new Runnable() { @Override public void run() { t.m1(); } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } new Thread(new Runnable() { @Override public void run() { t.m2(); } }).start(); } }
先解釋下線程的幾種狀態:
阻塞狀態: 包括普通阻塞,等待隊列,鎖池隊列。
普通阻塞: sleep(10000), 能夠被打斷。調用thread.interrupt()方法,能夠打斷阻塞狀態,拋出異常。
等待隊列: wait()方法被調用,也是一種阻塞狀態,只能由notify喚醒。沒法打斷
鎖池隊列: 沒法獲取鎖標記。不是全部的鎖池隊列均可被打斷blog
示例代碼
主線程啓動了兩個線程t1,t2,t1調用m1(),t2調用m2()
當主線程調用interrupt()方法,能夠打斷t2線程的阻塞等待鎖,拋出異常隊列
package com.bernardlowe.concurrent.t03; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Test_03 { Lock lock = new ReentrantLock(); void m1(){ try{ lock.lock(); for(int i = 0; i < 5; i++){ TimeUnit.SECONDS.sleep(1); System.out.println("m1() method " + i); } }catch(InterruptedException e){ e.printStackTrace(); }finally{ lock.unlock(); } } void m2(){ try{ lock.lockInterruptibly(); // 可嘗試打斷,阻塞等待鎖。能夠被其餘的線程打斷阻塞狀態 System.out.println("m2() method"); }catch(InterruptedException e){ System.out.println("m2() method interrupted"); }finally{ try{ lock.unlock(); }catch(Exception e){ e.printStackTrace(); } } } public static void main(String[] args) { final Test_03 t = new Test_03(); new Thread(new Runnable() { @Override public void run() { t.m1(); } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } Thread t2 = new Thread(new Runnable() { @Override public void run() { t.m2(); } }); t2.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t2.interrupt();// 打斷線程休眠。非正常結束阻塞狀態的線程,都會拋出異常。 } }
結果如圖
操做系統cpu,爲了保證效率,線程的執行機制是競爭機制,或者說是隨機機制,是不公平的,使用ReentrantLock實現公平鎖,是很是簡單的,只須要在建立ReentrantLock的時候傳一個參數ReentrantLock lock = new ReentrantLock(true);
示例代碼:
TestReentrantlock是公平鎖
TestSync是非公平鎖
/** * 公平鎖 */ package com.bernardlowe.concurrent.t03; import java.util.concurrent.locks.ReentrantLock; public class Test_04 { public static void main(String[] args) { TestReentrantlock t = new TestReentrantlock(); //TestSync t = new TestSync(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); t2.start(); } } class TestReentrantlock extends Thread{ // 定義一個公平鎖 private static ReentrantLock lock = new ReentrantLock(true); public void run(){ for(int i = 0; i < 5; i++){ lock.lock(); try{ System.out.println(Thread.currentThread().getName() + " get lock"); }finally{ lock.unlock(); } } } } class TestSync extends Thread{ public void run(){ for(int i = 0; i < 5; i++){ synchronized (this) { System.out.println(Thread.currentThread().getName() + " get lock in TestSync"); } } } }
公平鎖結果:
非公平鎖結果: