Java核心知識點 --- 線程中如何創建鎖和使用鎖 Lock , 設計一個緩存系統


理論知識很枯燥,但這些都是基本功,學完可能會忘,但等用的時候,會發覺之前的學習是非常有意義的,學習線程就是這樣子的. 

1.如何創建鎖?

Lock lock = new ReentrantLock();

2.如何使用鎖?

可以參看Lock文檔,其使用格式如下:

復制代碼
class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }
復制代碼

在要用的方法前加上鎖,比如寫操作,然后在finally中將鎖打開.

這里,將前文java核心知識點學習----多線程並發之線程同步中的代碼改用Lock實現數據同步,改寫代碼如下:

復制代碼
package com.amos.concurrent;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName: LockTest
 * @Description: Lock學習
 * @author: amosli
 * @email:hi_amos@outlook.com
 * @date Apr 22, 2014 1:48:36 AM
 */
public class LockTest {
    public static void main(String[] args) {
        new LockTest().init();
    }

    private void init() {
        final OutPuter outPuter = new OutPuter();
        // 新建一個線程
        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    // 休息10ms
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    outPuter.output("hi_amos");// 輸出
                }
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    outPuter.output("amosli");
                }
            }
        }).start();
    }

    static class OutPuter {
        // 方式1:使用synchronized關鍵字
        // public synchronized void output(String name) {
        // int length = name.length();
        // for (int i = 0; i < length; i++) {
        // System.out.print(name.charAt(i));
        // }
        // System.out.println();
        // }

        // 方式2:使用Lock鎖
        Lock lock = new ReentrantLock();

        public void output(String name) {
            lock.lock();// 加鎖
            int length = name.length();
            // 輸出name,逐個字節讀取,並輸出
            try {
                for (int i = 0; i < length; i++) {
                    System.out.print(name.charAt(i));
                }
                System.out.println();
            } finally {
                lock.unlock();// 解鎖
            }
        }
    }
}
復制代碼

3.synchronized關鍵字與Lock的區別?

1).Lock是Java5中的新特性,更加面向對象.更類似於生活中的鎖.

2).Lock鎖一般需要手動開啟和關閉,而synchronized則不需要.

建議優先使用Lock.

4.注意事項:

1)多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥.

2)要實現兩個線程互斥,那么要將鎖加到同一個被訪問對象上.

3)如果你的代碼修改數據,只能有一個人在寫,且不能同時讀取,那就上寫鎖,總之,讀的時候用讀鎖,寫的時候用寫鎖!

 

5.設計一個緩存系統

什么是緩存系統? 就是看本地是否已經緩存過此數據,如果已經緩存過,那就直接拿來用;如果沒有緩存過,那就查詢數據庫.

下面看代碼:

復制代碼
private Map<String, Object> cache = new HashMap<String, Object>();
    
    public synchronized Object getData(String key){
        Object object = cache.get(key);
        if (object==null) {
            object = "1323";//實際是去queryDB();
        }
        return object;
    }
復制代碼

這里其實是一個超級簡單的緩存系統,原理就是:第一次訪問的時候把值存入到cache中,第二次訪問時,先去看cache中是否有值如果有值,那么就直接去取值,而不是從數據庫中去取.

為什么要加上synchronized? 這是為了保持數據互斥,訪問的時候不相互影響,因為其中有對object進行賦值操作,這是一個寫操作,所以最好加上鎖.

如何優化?

復制代碼
private ReadWriteLock rwl = new ReentrantReadWriteLock();
    public synchronized Object getData(String key){
        rwl.readLock();//read lock
        Object object = cache.get(key);
        try{
        if (object==null) {
            rwl.readLock().unlock();//釋放鎖
            rwl.writeLock().lock();//對寫加鎖
            try{
                object = "1323";//實際是去queryDB();
            }finally{
                rwl.writeLock().unlock();
            }
        }
        }finally{
            rwl.readLock().unlock();
        }
        return object;
    }
復制代碼

 

上面的代碼運用到了剛學到的知識,對所有讀和寫進行加鎖,以保持線程間的互斥,要特別注意的是要在finally中把鎖打開,不管程序是否執行成功,因為如果不解鎖,那么程序將會產生死鎖,關於死鎖,將在接下來的文章中介紹.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM