简介
为了满足并发的要求,多个线程同时读取一个资源类应该可以同时进行,但是如果有一个线程想去写共享资源,此时就不应该再有其它线程可以对该资源进行读或写。
*独占锁(写)/共享锁(读)/互斥锁
-
独占锁
指该锁一次只能被一个线程所持有,ReentrantLock和synchronized都是独占锁
-
共享锁
指该锁可被多个线程所持有
*不加锁
会导致顺序混乱,数据不一致,如果使用lock的话,会导致读写都加锁,但是我们只需要给写加锁,不需要给读加锁
public class ReadWriteLockDemo{
public static void main(String[] args){
MyCache m = new MyCache();
for(int i = 1; i <= 5; i++){
final int tempNum = i;
new Thread(() -> {
m.put(tempNum + "" , tempNum + "");
},String.valueOf(i)).start();
}
for(int i = 1; i <= 5; i++){
final int tempNum = i;
new Thread(() -> {
m.get(tempNum + "");
},String.valueOf(i)).start();
}
}
}
class MyCache{
private volatile Map<String, Object> map = new HashMap<>();
/**
* 写操作的特征:原子+独占
* 整个过程必须是一个完整的统一体,中间不许被分割,被打断
*/
public void put(String k, Object v){
try{
System.out.println(Thread.currentThread().getName() + "\t开始写入" + k);
TimeUnit.MILLISECONDS.sleep(300);
map.put(k , v);
System.out.println(Thread.currentThread().getName() + "\t写入完成");
}catch(InterruptedException e){
e.printStackTrace();
}
}
/**
* 读的特征:可与其他线程共享资源,且时间不一样
*/
public void get(String k){
try{
System.out.println(Thread.currentThread().getName() + "\t开始读取");
TimeUnit.MILLISECONDS.sleep(300);
Object o = map.get(k);
System.out.println(Thread.currentThread().getName() + "\t读取完成" + o);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
读写锁
class MyCache{
private volatile Map<String, Object> map = new HashMap<>();
private ReadWriteLock r = new ReentrantReadWriteLock();
public void put(String k, Object v){
r.writeLock().lock();
try{
System.out.println(Thread.currentThread().getName() + "\t开始写入" + k);
TimeUnit.MILLISECONDS.sleep(300);
map.put(k , v);
System.out.println(Thread.currentThread().getName() + "\t写入完成");
}catch(InterruptedException e){
e.printStackTrace();
}finally{
r.writeLock().unlock();
}
}
public void get(String k){
r.readLock().lock();
try{
System.out.println(Thread.currentThread().getName() + "\t开始读取");
TimeUnit.MILLISECONDS.sleep(300);
Object o = map.get(k);
System.out.println(Thread.currentThread().getName() + "\t读取完成" + o);
}catch(InterruptedException e){
e.printStackTrace();
}finally{
r.readLock().unlock();
}
}
}
*总结
读的线程执行时,可以同时执行其它读的线程,但是不能执行写的线程
写的线程执行时,最好一个一个写入,不能执行读的线程