讀寫鎖:多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥。即:讀的時候不允許寫,寫的時候不允許讀,可以同時讀。
synchronized關鍵字和普通的Lock構造的鎖,會造成讀與讀之間的互斥,因此讀寫鎖可提高性能。
例子1:三個線程同時對一個共享數(shù)據(jù)進行讀寫。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockTest {
public static void main(String[] args) {
final Queue queue = new Queue();
for (int i = 0; i < 3; i++) {
new Thread() {
public void run() {
while (true) {
queue.get();
}
}
}.start();
new Thread() {
public void run() {
while (true) {
queue.put( new Random().nextInt(10000));
}
}
}.start();
}
}
}
class Queue {
PRivate Object data = null; // 共享數(shù)據(jù),只能有一個線程能寫該數(shù)據(jù),但可以有多個線程同時讀該數(shù)據(jù)。 ReadWriteLock rwl = new ReentrantReadWriteLock();
public void get() {
rwl.readLock().lock();
try {
System. out.println(Thread.currentThread().getName() + " be ready to read data!");
Thread. sleep((long) (Math. random() * 1000));
System. out.println(Thread.currentThread().getName() + " have read data :" + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwl.readLock().unlock();
}
}
public void put(Object data) {
rwl.writeLock().lock();
try {
System. out.println(Thread.currentThread().getName() + " be ready to write data!");
Thread. sleep((long) (Math. random() * 1000));
this.data = data;
System. out.println(Thread.currentThread().getName() + " have write data: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwl.writeLock().unlock();
}
}
}
例子2:緩存實例
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CacheDemo {
private static Map<String, Object> cache = new HashMap<String, Object>();
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public Object getData(String key) {
// 當線程開始讀時,首先開始加上讀鎖
rwl.readLock().lock();
Object value = null;
try {
value = cache.get(key);
// 判斷是否存在值
if (value == null) {
// 在開始寫之前,首先要釋放讀鎖,否則寫鎖無法拿到
rwl.readLock().unlock();
// 獲取寫鎖開始寫數(shù)據(jù)
rwl.writeLock().lock();
try {
// 再次判斷該值是否為空,因為如果兩個寫線程都阻塞在這里,
// 當一個線程被喚醒后value的值為null則進行數(shù)據(jù)加載,當另外一個線程也被喚醒如果不判斷就會執(zhí)行兩次寫
if (value == null) {
cache.put(key, value);
}
} finally {
rwl.writeLock().unlock(); // 釋放寫鎖
}
rwl.readLock().lock(); // 寫完之后降級為讀鎖
}
} finally {
rwl.readLock().unlock(); // 釋放讀鎖
}
return value;
}
}