1、可重入鎖ReentrantLock,相當於synchronized塊,為臨界區提供互斥訪問機制。
(1) 相關的接口
創建一個可重入鎖
- Lock lock = new ReentrantLock();
請求鎖,如果鎖被當前另一個線程持有,則阻塞。
- void lock();
釋放鎖
- void unlock();
非阻塞型lock()
- boolean tryLock();
(2) 使用基本結構
- locker.lock();
- try{
- //code here to Access the cirtical section
- }finally{
- locker.unlock();
- }
這種結構保證在任何時刻只有一個線程能夠進入臨界區,如果一個線程鎖住了鎖對象,其他任何線程在調用lock時,都會被阻塞,直到第一個線程釋放鎖對象。而且無論try塊是否拋出異常,都會執行finally block,解鎖locker。
(3) 鎖的可重入性
鎖是可重入的,線程能夠重復地獲取它已經擁有的鎖。鎖對象維護一個持有計數(hold count)來追蹤對lock方法的嵌套調用。線程在每次調用lock後都要調用unlock來釋放鎖。由於這個特性,被一個鎖保護的代碼可以調用另一個使用相同鎖的方法。
(4) 示例代碼:
- import Java.util.concurrent.locks.Lock;
- import Java.util.concurrent.locks.ReentrantLock;
- class WorkerOne extends Thread{
- private Lock locker;
- public WorkerOne (Lock locker){
- this.locker = locker;
- }
- public void run(){
- locker.lock();
- try{
- System.out.println(Thread.currentThread().getName()+":step into critical section");
- }finally{
- locker.unlock();
- }
- }
- }
- class WorkerTwo extends Thread{
- private Lock locker;
- public WorkerTwo (Lock locker){
- this.locker = locker;
- }
- public void sayHello(){
- locker.lock();
- try{ System.out.println(Thread.currentThread().getName()+":call sayHello()");
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }finally{
- locker.unlock();
- }
- }
- public void run(){
- locker.lock();
- try{ System.out.println(Thread.currentThread().getName()+":setp into critical section");
- //測試鎖的可重入性
- sayHello();
- }finally{
- locker.unlock();
- }
- }
- }
- public class Test5 {
- public static void main(String[] args) {
- Lock locker = new ReentrantLock();
- WorkerOne wo= new WorkerOne(locker);
- wo.setName("WorkerOne");
- WorkerTwo wt = new WorkerTwo(locker);
- wt.setName("WorkerTwo");
- wt.start();
- wo.start();
- }
- }
輸出:
WorkerTwo:setp into critical section WorkerTwo:call sayHello() WorkerOne:step into critical section
2、條件對象Condition,相當於wait-notify機制,提供一種線程間的等待通知機制,condition中的等待-通知方法是await(),signal(),signalAll(),也需要在互斥環境下被調用。
(1) 相關的接口
創建Condition對象,Condition對象是跟Lock關聯在一起的。
- Lock locker = new ReentrantLock();
- Condition cond = locker.newCondition();
把此線程放到條件的等待集中。
- void await();
解除此條件的等待集中所有線程的阻塞狀態。
- void signalAll();
在此條件的等待集中隨機選擇一個線程,解除其阻塞狀態。
- void signal();
(2) 使用的基本結構:
- //初始時ok_to_proceed為false.
- locker.lock()
- try{
- while(!ok_to_proceed){
- //進入等待此條件集中,被阻塞,它維持狀態直到另一個線程調用同一個條件上的。
- //signalAll/signal方法時為止。
- cond.await();
- }
- }finally{
- cker.unlock();
- }
- locker.lock();
- try{
- //調用將解除所有等待此條件下的線程的阻塞狀態。當線程從等待集中被移走時,它們將再次成為可運行的,調度器將再次激活它們
- //此時,它們將試圖重新進入對象。一旦鎖可獲得,它們中的某個線程將從await調用返回,從而獲得鎖並從它被阻塞的地方繼續執行。
- ok_to_proceed = true;
- cond.signalAll() or cond.signal();
- }finally{
- locker.unlock();
- }
ok_to_proceed也是為了防止wait-notify出現的問題,即再wait之間,notify()已經給出通知,此時wait只會一直等待下去,這樣就保證了signal()線程的通知被await()線程接收到。
(3) 測試代碼:
- import Java.util.concurrent.locks.Condition;
- import Java.util.concurrent.locks.Lock;
- import Java.util.concurrent.locks.ReentrantLock;
- class GlobalV{
- public final static Lock locker = new ReentrantLock();
- public final static Condition cond = locker.newCondition();
- public static boolean to_proceed = false;
- }
- class Response extends Thread{
- public void run(){
- while(true){
- GlobalV.locker.lock();
- try{
- while(!GlobalV.to_proceed){
- GlobalV.cond.await();
- }
- System.out.println("Response:finish a job");
- GlobalV.to_proceed = false;
- }catch(Exception e){
- e.printStackTrace();
- }finally{
- GlobalV.locker.unlock();
- }
- }
- }
- }
- class Request extends Thread{
- public void run(){
- while(true){
- GlobalV.locker.lock();
- try{
- GlobalV.to_proceed = true;
- GlobalV.cond.signalAll();
- System.out.println("Request:send a job to Response");
- }finally{
- GlobalV.locker.unlock();
- }
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- public class Test6 {
- public static void main(String[] args) {
- Request req = new Request();
- Response res = new Response();
- req.start();
- res.start();
- }
- }
輸出:
Request:send a job to Response Response:finish a job Request:send a job to Response Response:finish a job Request:send a job to Response Response:finish a job Request:send a job to Response Response:finish a job