在使用某些种类的 Collection 时,可以使用 ReentrantReadWriteLock 来提高并发性。通常,在预期 collection 很大,读取者线程访问它的次数多于写入者线程,并且 entail 操作的开销高于同步开销时,这很值得一试。例如,以下是一个使用 TreeMap 的类,预期它很大,并且能被同时访问
代码实例:
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 读写锁的使用
*
*/
public class ReentrantReadWriteLockMap<T> {
private final Map<String,T> treeMap=new TreeMap<String,T>();
/** 公平策略的读写锁 */
private final ReentrantReadWriteLock rwl=new ReentrantReadWriteLock(true);
private final Lock rl=rwl.readLock();
private final Lock wl=rwl.writeLock();
public T get(String key){
rl.lock();
try{
return treeMap.get(key);
}finally{
rl.unlock();
}
}
public String[] allKeys() {
rl.lock();
try{
return (String[]) treeMap.keySet().toArray();
}finally{
rl.unlock();
}
}
public T put(String key ,T value){
wl.lock();
try{
return treeMap.put(key, value);
}finally{
wl.unlock();
}
}
public void clear(){
wl.lock();
try{
treeMap.clear();
}finally{
wl.unlock();
}
}
public static void main(String[] args) {
final ReentrantReadWriteLockMap<String> map=new ReentrantReadWriteLockMap<String>();
new Thread(){
public void run(){
for(int i=1;i<=10000;i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put("key:"+i, Integer.toString(i));
}
}
}.start();
new Thread(){
public void run(){
for(int i=1;i<=10000;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
String t=map.get("key:"+i);
if(t==null||"".equals(t)){
}
System.out.println(map.get("key:"+i));
}
}
}.start();
}
}
允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不可能的。
代码实例:
/**
* 摘抄自JDK文档的伪代码
*/
class CachedData {
Object data;
volatile boolean cacheValid;
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
// Recheck state because another thread might have acquired
// write lock and changed state before we did.
if (!cacheValid) {
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
rwl.writeLock().unlock(); // Unlock write, still hold read
}
use(data);
rwl.readLock().unlock();
}
}