使用场景:
程序中有如下三种互斥情况:读/读,写/写,读/写。在大多数情况下我们只需要控制读/写,写/写两种情况互斥即可,读/读操作不用做同步。当程序中读/读操作的比例较大时,如果还使用ReentrantLock,则其同步机制会照成大量的排队。可是使用ReadWriteLock可以极大的提高程序的性能。
ReentrantLock和ReadWriteLock使用起来基本一致。下面测试下两者在频繁进行读操作时的性能。
开三个线程分别进行循环10次的写操作,开1000个线程进行读操作。
ReentrantLock 性能测试:
public class P2_ReadWriteLock {
String name;
ReentrantLock lock = new ReentrantLock();
// ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void setName(String name) {
lock.lock();
// lock.writeLock().lock();
try {
this.name = name;
System.out.println(Thread.currentThread().getName() + " setName " + this.name);
//假设该类型操作消耗一点时间
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
// lock.writeLock().unlock();
}
}
public void printName() {
lock.lock();
// lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " name is " + name);
//假设该类型操作需要消耗一点时间
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
// lock.readLock().unlock();
}
}
public static void main(String[] args) {
P2_ReadWriteLock client = new P2_ReadWriteLock();
long startTime = System.currentTimeMillis();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
client.setName(Thread.currentThread().getName());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
client.setName(Thread.currentThread().getName());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
client.setName(Thread.currentThread().getName());
}
}
}).start();
new Date().getTime();
for (int i = 0; i < 1000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
client.printName();
System.out.println(Thread.currentThread().getName() + " 耗时:" + (System.currentTimeMillis() - startTime));
}
}).start();
}
}
}
结果:
Thread-999 耗时:11028
Thread-1000 name is Thread-2
Thread-1000 耗时:11039
Thread-1001 name is Thread-2
Thread-1001 耗时:11050
Thread-1002 name is Thread-2
Thread-1002 耗时:11061
ReadWriteLock:
public class P2_ReadWriteLock {
String name;
// ReentrantLock lock = new ReentrantLock();
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void setName(String name) {
// lock.lock();
lock.writeLock().lock();
try {
this.name = name;
System.out.println(Thread.currentThread().getName() + " setName " + this.name);
//假设该类型操作消耗一点时间
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// lock.unlock();
lock.writeLock().unlock();
}
}
public void printName() {
// lock.lock();
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " name is " + name);
//假设该类型操作需要消耗一点时间
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// lock.unlock();
lock.readLock().unlock();
}
}
public static void main(String[] args) {
P2_ReadWriteLock client = new P2_ReadWriteLock();
long startTime = System.currentTimeMillis();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
client.setName(Thread.currentThread().getName());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
client.setName(Thread.currentThread().getName());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
client.setName(Thread.currentThread().getName());
}
}
}).start();
new Date().getTime();
for (int i = 0; i < 1000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
client.printName();
System.out.println(Thread.currentThread().getName() + " 耗时:" + (System.currentTimeMillis() - startTime));
}
}).start();
}
}
}
结果:
Thread-561 耗时:448
Thread-552 耗时:448
Thread-559 耗时:448
Thread-551 耗时:448
Thread-549 耗时:448
总结:
当满足读/写互斥,写/写互斥,而读/读不需要互斥,且读/读操作的比例比较大时,换成读写锁更好。
网友评论