学习:https://blog.youkuaiyun.com/u012506661/article/details/53157004
1,synchronized的锁是不分读写的,假设一个对象有读方法还有写方法,我们希望读方法和写方法能不同线程访问,所以读写锁解决了这个问题,当写操作时,其他线程无法读取或者写数据,而读操作时,其他线程虽然无法写数据,但是可以读数据,也就是说,读可以多线程共享。
2,读写锁:分为读锁和写锁,多读不互斥,读写互斥,也就是说写的时候只能一个人写并且不能读,读可以多人同时读但不能写。总之读就上读锁,写就上写锁
3,线程进入读锁前提:没有其他线程写锁,没有写的请求或者有写请求,但调用线程和持有线程是同一个。
线程进入写锁前提:没有其他线程读,没有其他线程写
4,特性:
a,重入方面其内部的写锁可以获取读锁,但反过来不行。
b,写锁可以降级读锁,顺序是先写锁获得读锁,然后释放写锁,这个时候该线程保持读锁的拥有,反过来不行。
c,读锁可以被多个线程持有并且排斥写锁,而写锁则是完全互斥。
d,不管读还是写,都支持中断。
e,写支持Condition并且语义与ReentrantLock一样,但是读锁不能用Condition,会抛出异常。
5,使用
package com.study.webapp.lock;
import java.util.Random;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReentrantReadWriterLockTest {
public static void main(String[] args) {
ReentrantReadWriterLockTest t = new ReentrantReadWriterLockTest();
ReentrantReadWriterLockTest.model m = t.new model();
for (int i = 0; i < 3; i++) {
new Thread() {
public void run() {
m.get();
}
}.start();
}for (int i = 0; i < 3; i++) {
new Thread() {
public void run() {
m.put(new Random().nextInt(10000));
}
}.start();
}
}class model {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private Object data = null;public void get() {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + ">>读锁");
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (Exception e) {}
System.out.println(Thread.currentThread().getName() + ">>读锁>>" + data);
lock.readLock().unlock();
}public void put(Object data) {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName() + ">>>>写锁");
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (Exception e) {}
this.data = data;
System.out.println(Thread.currentThread().getName() + ">>写锁>>" + data);
lock.writeLock().unlock();
}
}
}
5.2 锁的降级
package com.study.webapp.lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class WriteToRead {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void CachedData() {
lock.readLock().lock();
// 做某些操作
System.out.println(Thread.currentThread().getName());
// 获取写锁前一定要先释放读锁
lock.readLock().unlock();
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName());
// 在释放写锁前可以获取读锁
lock.readLock().lock();
lock.writeLock().unlock();
// 释放完写锁再释放读锁
lock.readLock().unlock();
}}
6,源码分析