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的优势在于允许多个线程同时读,可以加快速度。如果在读操作不是非常多的情况下或者读操作的时间非常短的情况下,性能差异会变小。