标签:io ar 使用 sp java strong on 数据 art
从这一节开始介绍锁里面的最后一个工具:读写锁(ReadWriteLock)。
ReentrantLock 实现了标准的互斥操作,也就是一次只能有一个线程持有锁,也即所谓独占锁的概念。前面的章节中一直在强调这个特点。显然这个特点在一定程度上面减低了吞吐量,实际上独占锁是一种保守的锁策略,在这种情况下任何“读/读”,“写/读”,“写/写”操作都不能同时发生。但是同样需要强调的一个概念是,锁是有一定的开销的,当并发比较大的时候,锁的开销就比较客观了。所以如果可能的话就尽量少用锁,非要用锁的话就尝试看能否改造为读写锁。
ReadWriteLock描述的是:一个资源能够被多个读线程访问,或者被一个写线程访问,但是不能同时存在读写线程。也就是说读写锁使用的场合是一个共享资源被大量读取操作,而只有少量的写操作(修改数据)。清单1描述了ReadWriteLock的API。
清单1 ReadWriteLock 接口
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
清单1描述的ReadWriteLock结构,这里需要说明的是ReadWriteLock并不是Lock的子接口,只不过ReadWriteLock借助Lock来实现读写两个视角。在ReadWriteLock中每次读取共享数据就需要读取锁,当需要修改共享数据时就需要写入锁。看起来好像是两个锁,但其实不尽然,在下一节中的分析中会解释这点奥秘。
在JDK 6里面ReadWriteLock的实现是ReentrantReadWriteLock。
清单2 SimpleConcurrentMap
package xylz.study.concurrency.lock;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class SimpleConcurrentMap<K, V> implements Map<K, V> {
final ReadWriteLock lock = new ReentrantReadWriteLock();
final Lock r = lock.readLock();
final Lock w = lock.writeLock();
final Map<K, V> map;
public SimpleConcurrentMap(Map<K, V> map) {
this.map = map;
if (map == null) throw new NullPointerException();
}public void clear() {
w.lock();
try {
map.clear();
} finally {
w.unlock();
}
}public boolean containsKey(Object key) {
r.lock();
try {
return map.containsKey(key);
} finally {
r.unlock();
}
}public boolean containsValue(Object value) {
r.lock();
try {
return map.containsValue(value);
} finally {
r.unlock();
}
}public Set<java.util.Map.Entry<K, V>> entrySet() {
throw new UnsupportedOperationException();
}public V get(Object key) {
r.lock();
try {
return map.get(key);
} finally {
r.unlock();
}
}public boolean isEmpty() {
r.lock();
try {
return map.isEmpty();
} finally {
r.unlock();
}
}public Set<K> keySet() {
r.lock();
try {
return new HashSet<K>(map.keySet());
} finally {
r.unlock();
}
}public V put(K key, V value) {
w.lock();
try {
return map.put(key, value);
} finally {
w.unlock();
}
}public void putAll(Map<? extends K, ? extends V> m) {
w.lock();
try {
map.putAll(m);
} finally {
w.unlock();
}
}public V remove(Object key) {
w.lock();
try {
return map.remove(key);
} finally {
w.unlock();
}
}public int size() {
r.lock();
try {
return map.size();
} finally {
r.unlock();
}
}public Collection<V> values() {
r.lock();
try {
return new ArrayList<V>(map.values());
} finally {
r.unlock();
}
}}
清单2描述的是用读写锁实现的一个线程安全的Map。其中需要特别说明的是并没有实现entrySet()方法,这是因为实现这个方法比较复杂,在后面章节中讲到ConcurrentHashMap的时候会具体谈这些细节。另外这里keySet()和values()也没有直接返回Map的视图,而是一个映射原有元素的新视图,其实这个entrySet()一样,是为了保护原始Map的数据逻辑,防止不正确的修改导致原始Map发生数据错误。特别说明的是在没有特别需求的情况下没有必要按照清单2写一个线程安全的Map实现,因为ConcurrentHashMap已经完成了此操作。
ReadWriteLock需要严格区分读写操作,如果读操作使用了写入锁,那么降低读操作的吞吐量,如果写操作使用了读取锁,那么就可能发生数据错误。
另外ReentrantReadWriteLock还有以下几个特性:
UnsupportedOperationException
异常。上面几个特性对读写锁的理解很有帮助,而且也是必要的,另外在下一节中讲ReadWriteLock的实现会用到这些知识的。
深入浅出 Java Concurrency (13): 锁机制 part 8 读写锁 (ReentrantReadWriteLock) (1)[转]
标签:io ar 使用 sp java strong on 数据 art
原文地址:http://www.cnblogs.com/0x2D-0x22/p/4138679.html