Java 並發編程中使用 ReentrantLock 替代 synchronized 關鍵字原語

來源:互聯網
上載者:User

Java 並發編程中使用 ReentrantLock 替代 synchronized 關鍵字原語
標籤:Java 5 引入的 Concurrent 並發庫軟體包中,提供了 ReentrantLock 可重新進入同步鎖,用來替代 synchronized 關鍵字原語,並可提供更好的效能,以及更強大的功能。使用方法也很簡單: public final ReentrantLock lock=new ReentrantLock();......try {    lock.lock();    // 進入同步內容    ....} finally {    lock.unlock(); // 必須在 finally 塊中解鎖,否則一旦出現異常,執行不到解鎖,則一直鎖住了。} synchronized原語和ReentrantLock在一般情況下沒有什麼區別,但是在非常複雜的同步應用中,請考慮使用ReentrantLock,特別是遇到下面2種需求的時候。 1.某個線程在等待一個鎖的控制權的這段時間需要中斷 2.需要分開處理一些wait-notify,ReentrantLock裡面的Condition應用,能夠控制notify哪個線程 3.具有公平鎖功能,每個到來的線程都將排隊等候  先說第一種情況,ReentrantLock的lock機制有2種,忽略中斷鎖和響應中斷鎖,這給我們帶來了很大的靈活性。比如:如果A、B2個線程去競爭鎖,A線程得到了鎖,B線程等待,但是A線程這個時候實在有太多事情要處理,就是一直不返回,B線程可能就會等不及了,想中斷自己,不再等待這個鎖了,轉而處理其他事情。這個時候ReentrantLock就提供了2種機制,第一,B線程中斷自己(或者別的線程中斷它),但是ReentrantLock不去響應,繼續讓B線程等待,你再怎麼中斷,我全當耳邊風(synchronized原語就是如此);第二,B線程中斷自己(或者別的線程中斷它),ReentrantLock處理了這個中斷,並且不再等待這個鎖的到來,完全放棄。(如果你沒有瞭解java的中斷機制,請參考下相關資料,再回頭看這篇文章,80%的人根本沒有真正理解什麼是java的中斷,呵呵)  這裡來做個實驗,首先搞一個Buffer類,它有讀操作和寫操作,為了不讀到髒資料,寫和讀都需要加鎖,我們先用synchronized原語來加鎖,如下: 

public class Buffer {             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讀資料");            }        }    }   

 

 接著,我們來定義2個線程,一個線程去寫,一個線程去讀。  
public class Writer extends Thread {             private Buffer buff;             public Writer(Buffer buff) {            this.buff = buff;        }             @Override        public void run() {            buff.write();        }         }         public class Reader extends Thread {             private Buffer buff;             public Reader(Buffer buff) {            this.buff = buff;        }             @Override        public void run() {                 buff.read();//這裡估計會一直阻塞                 System.out.println("讀結束");             }         }   

 

 好了,寫一個Main來實驗下,我們有意先去“寫”,然後讓“讀”等待,“寫”的時間是無窮的,就看“讀”能不能放棄了。  
public class Test {        public static void main(String[] args) {            Buffer buff = new Buffer();                 final Writer writer = new Writer(buff);            final Reader reader = new Reader(buff);                 writer.start();            reader.start();                 new Thread(new Runnable() {                     @Override                public void run() {                    long start = System.currentTimeMillis();                    for (;;) {                        //等5秒鐘去中斷讀                        if (System.currentTimeMillis()                                - start > 5000) {                            System.out.println("不等了,嘗試中斷");                            reader.interrupt();                            break;                        }                         }                     }            }).start();             }    }   

 

  我們期待“讀”這個線程能退出等待鎖,可是事與願違,一旦讀這個線程發現自己得不到鎖,就一直開始等待了,就算它等死,也得不到鎖,因為寫線程要21億秒才能完成 T_T ,即使我們中斷它,它都不來響應下,看來真的要等死了。這個時候,ReentrantLock給了一種機制讓我們來響應中斷,讓“讀”能伸能屈,勇敢放棄對這個鎖的等待。我們來改寫Buffer這個類,就叫BufferInterruptibly吧,可中斷緩衝。  
import java.util.concurrent.locks.ReentrantLock;         public class BufferInterruptibly {             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();            }        }         }   

 

 當然,要對reader和writer做響應的修改  
public class Reader extends Thread {             private BufferInterruptibly buff;             public Reader(BufferInterruptibly buff) {            this.buff = buff;        }             @Override        public void run() {                 try {                buff.read();//可以收到中斷的異常,從而有效退出            } catch (InterruptedException e) {                System.out.println("我不讀了");            }                       System.out.println("讀結束");             }         }             public class Writer extends Thread {             private BufferInterruptibly buff;             public Writer(BufferInterruptibly buff) {            this.buff = buff;        }             @Override        public void run() {            buff.write();        }         }         public class Test {        public static void main(String[] args) {            BufferInterruptibly buff = new BufferInterruptibly();                 final Writer writer = new Writer(buff);            final Reader reader = new Reader(buff);                 writer.start();            reader.start();                 new Thread(new Runnable() {                     @Override                public void run() {                    long start = System.currentTimeMillis();                    for (;;) {                        if (System.currentTimeMillis()                                - start > 5000) {                            System.out.println("不等了,嘗試中斷");                            reader.interrupt();                            break;                        }                         }                     }            }).start();             }    }   

 


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.