ReadWriteLock和ReetrantLock
ReetrantLock是Lock框架的下的一個實現,實現對對象的鎖定,用在保證線程安全,ReadWriteLock和ReetrantLock的功能類似。那麼它們之間的區別是什麼?以及各自使用於哪些場景。
ReadWriteLock相對於ReetrantLock的優勢
ReadWriteLock顧名思義:讀寫鎖,當讀鎖佔有的時候,允許別的讀操作。而如果進行寫操作,不允許別的線程進行讀和寫。例如對一個隊列進行操作的時候,如果用ReetrantLock來保證線程安全的話,當讀操作的時候也會阻止別的讀操作,性能產生影響。
測試
我們寫代碼來測試一下,看一下到底性能的影響程度。
public class RWDictionary {
private final Map<String, String> map = new TreeMap<String, String>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
public String get(String key) {
readLock.lock();
try {
try {
Thread.sleep(10);//爲了增加讀操作的時間,使測試效果更好
} catch (InterruptedException e) {
e.printStackTrace();
}
return map.get(key);
} finally {
readLock.unlock();
}
}
public void put(String key, String value) {
writeLock.lock();
try {
map.put(key, value);
} finally {
writeLock.unlock();
}
}
}
這裏我們定義了一個讀寫鎖,然後利用讀寫鎖在讀寫的時候進行lock()操作來保證線程安全。
public class ReetrantLockTest {
private final Map<String, String> map = new TreeMap<String, String>();
private final ReentrantLock lock = new ReentrantLock();
public String get(String key) {
lock.lock();
try {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
return map.get(key);
} finally {
lock.unlock();
}
}
public void put(String key, String value) {
lock.lock();
try {
map.put(key, value);
} finally {
lock.unlock();
}
}
}
我們在這裏定義了同樣的一個類,只是這次在讀取數據的時候換用了ReetrantLock來進行數據的鎖定。
下面我們定義不同類的讀線程。
public class RWDctionnaryTestGetThread implements Runnable{
private RWDictionary rwDictionary;
public RWDctionnaryTestGetThread(RWDictionary rw){
this.rwDictionary=rw;
}
public void run() {
for(int i=0;i<10;i++){
rwDictionary.get(i+"");
}
}
}
在這個讀線程我們讀取RWDictionary。
public class DictionaryTestGetThread implements Runnable{
private ReetrantLockTest reetrantLockTest;
public DictionaryTestGetThread(ReetrantLockTest rw){
this.reetrantLockTest=rw;
}
public void run() {
for(int i=0;i<10;i++){
reetrantLockTest.get(i+"");
}
}
}
在這個讀線程讀取ReetrantLockTest。
下面我們來寫我們的測試用例:
public class RWDictionaryTest {
public static void main(String args[]) {
List<Thread> threadList = new ArrayList<Thread>();
RWDictionary rwDictionary = new RWDictionary();
long startTime = System.nanoTime();
for (int i = 0; i < 100; i++) {
Thread getThread = new Thread(new RWDctionnaryTestGetThread(rwDictionary));
// Thread putThread=new Thread(new RWDctionaryTestPutThread(rwDictionary));
getThread.start();
// putThread.start();
threadList.add(getThread);
// threadList.add(putThread);
}
for (Thread thread : threadList) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("cost time:" + (System.nanoTime() - startTime));
threadList.clear();
ReetrantLockTest reetrantLockTest = new ReetrantLockTest();
startTime = System.nanoTime();
for (int i = 0; i < 100; i++) {
Thread getThread = new Thread(new DictionaryTestGetThread(reetrantLockTest));
// Thread putThread=new Thread(new DictionaryTestPutThread(reetrantLockTest));
getThread.start();
// putThread.start();
threadList.add(getThread);
// threadList.add(putThread);
}
for (Thread thread : threadList) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("cost time:" + (System.nanoTime() - startTime));
}
}
在上面的代碼中,我們用定義了多個線程來進行測試,運行測試效果如下:
結論
ReadWriteLock相對於ReetrantLock的優勢在於允許多個線程同時讀,可以加快速度。如果在讀操作不是非常多的情況下或者讀操作的時間非常短的情況下,性能差異會變小。