在Java多線程中,可以使用關鍵字Synchronized實現線程之間互斥。在JDK1.5之後,提供了線程並發庫java.util.concurrent用於操作多線程,其中包含了java.util.concurrent.atomic和java.util.concurrent.lock。atomic可以實現資料或變數的原子性操作,而lock可以實現線程互斥,可以實現讀寫鎖,跟Synchronized一樣同屬於可重新進入鎖,但在使用上比Synchronized更加靈活。
在代碼中,可以通過new ReentrantLock()建立一個lock鎖,調用lock()實現對代碼上鎖,調用unlock()可以解鎖。當然,為了保證代碼運行出現異常時也能解鎖,應該把上鎖的代碼用try包裹起來,並在finally裡解鎖,具體代碼實現如下:
public class Main { //靜態內部類實現線程共用 static class Example{ //建立lock Lock lock = new ReentrantLock(); public void outPut(String str){ //上鎖 lock.lock(); try{ for(int i=0;i<str.length();i++){ System.out.print(str.charAt(i)); } System.out.print("\n"); }finally { //解鎖 lock.unlock(); } } } public static void main(String[] args) { final Example example = new Example(); new Thread(new Runnable() { @Override public void run() { while (true){ example.outPut("str1"); } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true){ example.outPut("str2"); } } }).start(); }}
對於lock的讀寫鎖,可以通過new ReentrantReadWriteLock()擷取到一個讀寫鎖。所謂讀寫鎖,便是多線程之間讀不互斥,讀寫互斥。讀寫鎖是一種自旋鎖,如果當前沒有讀者,也沒有寫者,那麼寫者可以立刻獲得鎖,否則它必須自旋在那裡,直到沒有任何寫者或讀者。如果當前沒有寫者,那麼讀者可以立即獲得該讀寫鎖,否則讀者必須自旋在那裡,直到寫者釋放該鎖。具體代碼實現如下:
public class Main { //靜態內部類實現線程共用 static class Example{ //建立lock ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); //讀操作 public void read(){ //擷取讀鎖並上鎖 lock.readLock().lock(); try{ System.out.println("讀線程開始"); Thread.sleep(1000); System.out.println("讀線程結束"); }catch (Exception e){ e.printStackTrace(); }finally{ //解鎖 lock.readLock().unlock(); } } //寫操作 public void write(){ //擷取寫鎖並上鎖 lock.writeLock().lock(); try{ System.out.println("寫線程開始"); Thread.sleep(1000); System.out.println("寫線程結束"); }catch (Exception e){ e.printStackTrace(); }finally { //解鎖 lock.writeLock().unlock(); } } } public static void main(String[] args) { final Example example = new Example(); new Thread(new Runnable() { @Override public void run() { while (true){ example.read(); example.write(); } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true){ example.read(); example.write(); } } }).start(); }}
運行結果:
根據結果可以發現,多線程下ReentrantReadWriteLock可以多線程同時讀,但寫的話同一時刻只有一個線程執行。
最後說一說讀寫鎖的應用情境,我們可以利用讀寫鎖可是實現一個多線程下資料緩衝的功能,具體實現思路如下:
class dataCatch{ Object data; //緩衝的資料 public volatile Boolean isCatch = false; //是否有緩衝 ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); //產生讀寫鎖 public void process(){ lock.readLock().lock(); //先加讀鎖,此時資料不會被修改 //資料沒有緩衝 if(!isCatch){ lock.readLock().unlock(); //解讀鎖 lock.writeLock().lock(); //加寫鎖,此時資料不會被讀到 /******** * * 執行資料查詢操作並賦值給data * ********/ isCatch = true; lock.readLock().lock(); //先加讀鎖後解寫鎖 lock.writeLock().lock(); } /******** * * 放回data資料給使用者 * ********/ lock.readLock().unlock(); //解讀鎖 }}