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

標籤:java

Java 5 引入的 Concurrent 併發庫軟件包中,提供了 ReentrantLock 可重入同步鎖,用來替代 synchronized 關鍵字原語,並可提供更好的性能,以及更強大的功能。使用方法也很簡單:mysql

 

public final ReentrantLock lock=new ReentrantLock();sql

......數據庫

try {緩存

    lock.lock();安全

    // 進入同步內容mybatis

    ....併發

} finally {oracle

    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();    
     
    }    
}   

此次「讀」線程接收到了lock.lockInterruptibly()中斷,而且有效處理了這個「異常」。


獲取【下載地址】   QQ: 313596790   【免費支持更新】
A 代碼生成器(開發利器);所有是源碼  
   增刪改查的處理類,service層,mybatis的xml,SQL( mysql   和oracle)腳本,   jsp頁面 都生成
   就不用寫搬磚的代碼了,生成的放到項目裏,能夠直接運行
B 阿里巴巴數據庫鏈接池druid;
  數據庫鏈接池  阿里巴巴的 druid。Druid在監控、可擴展性、穩定性和性能方面都有明顯的優點
C 安全權限框架shiro ;
  Shiro 是一個用 Java 語言實現的框架,經過一個簡單易用的 API 提供身份驗證和受權,更安全,更可靠
D ehcache 分佈式緩存;
  是一個純Java的進程內緩存框架,具備快速、精幹等特色,普遍使用的開源Java分佈式緩存

相關文章
相關標籤/搜索