理论
独占锁:指该锁一次只能被一个线程所持有。对于ReentrantLock和Synchronized而言都是独占锁。
共享锁:该锁可以被多个线程所持有。对于ReentrantReadWriteLock来说,其读锁是共享锁,写锁是独占锁。读锁的共享锁可保证并发读是非常高效的,读写,写读,读读的过程是互斥的。
代码验证
加锁前:
package locks;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class MyCache{
private volatile Map<String,Object> map = new HashMap<>();
public void put(String key,Object value){
System.out.println(Thread.currentThread().getName()+"\t 正在写入:"+key);
try{
TimeUnit.SECONDS.sleep(3);
}catch(InterruptedException e){
e.printStackTrace();
}
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"\t 写入完成:");
}
public void get(String key){
System.out.println(Thread.currentThread().getName()+"\t 正在读取:");
try{
TimeUnit.SECONDS.sleep(3);
}catch(InterruptedException e){
e.printStackTrace();
}
Object result = map.get(key);
System.out.println(Thread.currentThread().getName()+"\t 读取完成:"+result);
}
public static void main(String[] args) {
MyCache myCache = new MyCache();
for(int i=1; i <= 5 ; i++){
final int tempInt = i;
new Thread(()->{
myCache.put(tempInt+"",tempInt+"");
},String.valueOf(i)).start();
}
for(int i=1; i <= 5 ; i++){
final int tempInt = i;
new Thread(()->{
myCache.get(tempInt+"");
},String.valueOf(i)).start();
}
}
}
public class ReadWriteLockDemo {
public static void main(String[] args) {
}
}
可以看到,在写的过程中,并不是独占的。
加入ReentrantReadWriteLock后:
package locks;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class MyCache{
//写操作:原子+独占,整个过程必须是一个完整的统一体,不可以被分割和打断。
private volatile Map<String,Object> map = new HashMap<>();
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void put(String key,Object value){
lock.writeLock().lock();
try{
System.out.println(Thread.currentThread().getName()+"\t 正在写入:"+key);
try{
TimeUnit.SECONDS.sleep(3);
}catch(InterruptedException e){
e.printStackTrace();
}
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"\t 写入完成:");
} catch(Exception e){
e.printStackTrace();
}finally{
lock.writeLock().unlock();
}
}
public void get(String key){
lock.readLock().lock();
try{
System.out.println(Thread.currentThread().getName()+"\t 正在读取:");
try{
TimeUnit.SECONDS.sleep(3);
}catch(InterruptedException e){
e.printStackTrace();
}
Object result = map.get(key);
System.out.println(Thread.currentThread().getName()+"\t 读取完成:"+result);
} catch(Exception e){
e.printStackTrace();
}finally{
lock.readLock().unlock();
}
}
public static void main(String[] args) {
MyCache myCache = new MyCache();
for(int i=1; i <= 5 ; i++){
final int tempInt = i;
new Thread(()->{
myCache.put(tempInt+"",tempInt+"");
},String.valueOf(i)).start();
}
for(int i=1; i <= 5 ; i++){
final int tempInt = i;
new Thread(()->{
myCache.get(tempInt+"");
},String.valueOf(i)).start();
}
}
}
public class ReadWriteLockDemo {
public static void main(String[] args) {
}
}
可以看到写操作被严格控制,写独占,读共享,既保证了写时的正确性,又保证的读的并发性。