1,从名字上看就是一种比较特殊的锁,该锁能针对读和写操作分别对读线程和写线程进行不同的处理,确保不会出现冲突情况
2,适用范围,对于共享资源,如果两个线程同时进行读操作是不会发生任何冲突的,因为读操作不会修改共享资源的值。但如果一个线程在读,另外一个线程在写,或者两个线程同时进行写操作,那么就会发生冲突,Read-write Lock模式就是用于这种场景下,一方面同时读不加锁提高性能,另一方面防止出现读写或写写冲突。
3,实现方式,这里有4个概念,Reader进行读操作的线程,Writer进行写操作线程,SharedResouce共享资源,ReadWriteLock读写锁,其中ReadWriteLock是核心,他增加了3个变量,分别是正在进行读的线程数,正在进行写操作的线程数,等待进行写操作的线程数,利用这3个变量来控制当前线程在请求锁的时候是否需要等待。
4,代码实现
1)定义读写锁类,具体看代码注解
package readwritelock.study;
public class ReadWriteLock {
public int readingThreadNum=0; //实际正在进行读操作的线程数
public int writingThreadNum=0; //实际正在进行写操作的线程数
public int waitingWriteThreadNum=0; //正在等待写入操作的线程数
public synchronized void readLock()
{
//存在着正在进行写操作或有线程等待申请写锁,此时不能申请读锁
while (writingThreadNum>0||waitingWriteThreadNum>0) {
try {
System.out.println("Thread name:"+Thread.currentThread().getName()+" waiting to get readLock ");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread name:"+Thread.currentThread().getName()+" get readLock ");
readingThreadNum++;
}
//释放写锁
public synchronized void readUnlock()
{
readingThreadNum--;
System.out.println("Thread name:"+Thread.currentThread().getName()+" release readLock ");
notifyAll();
}
public synchronized void writeLock()
{
waitingWriteThreadNum++;
try {
//存在着正在进行读操作的线程或者正在进行写操作的线程,此时不能申请写锁
while (readingThreadNum > 0 || writingThreadNum > 0) {
System.out.println("Thread name:"+Thread.currentThread().getName()+" waiting to get writeLock ");
wait();
}
}
catch (Exception e) {
e.printStackTrace();
}finally {
waitingWriteThreadNum--;
}
System.out.println("Thread name:"+Thread.currentThread().getName()+" get writeLock ");
writingThreadNum++;
}
//释放写锁
public synchronized void writeUnlock()
{
writingThreadNum--;
System.out.println("Thread name:"+Thread.currentThread().getName()+" release wirteLock ");
notifyAll();
}
}
2)定义共享资源类,利用读写锁控制读写操作
package readwritelock.study;
public class SharedResource {
private String resource="Resource1";
ReadWriteLock readWriteLock=new ReadWriteLock();
public void read()
{
readWriteLock.readLock();
System.out.println("Thread name:"+Thread.currentThread().getName()+" read shared resource:"+ resource);
readWriteLock.readUnlock();
}
public void wirte(String newResource)
{
readWriteLock.writeLock();
resource=newResource;
System.out.println("Thread name:"+Thread.currentThread().getName()+" set shared resource:"+ resource);
readWriteLock.writeUnlock();
}
}
3)开启4条线程,分别2条读线程,2条写线程,读线程进行2次读操作,写线程进行1次写操作
package readwritelock.study;
import java.util.Random;
public class ReadWirteLockTest {
public static void main(String[] args) {
SharedResource sharedResource=new SharedResource();
Thread read1=new Thread(
new Runnable() {
@Override
public void run() {
Random random=new Random(8);
for(int i=0;i<2;i++) {
try {
sharedResource.read();
Thread.sleep(random.nextInt(100));//随机降低线程执行速度
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
);
Thread read2=new Thread(
new Runnable() {
@Override
public void run() {
Random random=new Random(8);
for(int i=0;i<2;i++) {
try {
sharedResource.read();
Thread.sleep(random.nextInt(100));//随机降低线程执行速度
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
);
Thread write1=new Thread(
new Runnable() {
@Override
public void run() {
Random random=new Random(5);
for(int i=0;i<1;i++) {
try {
sharedResource.wirte("write thread1_"+i);
Thread.sleep(random.nextInt(100));//随机降低线程执行速度
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
);
Thread write2=new Thread(
new Runnable() {
@Override
public void run() {
Random random=new Random(5);
for(int i=0;i<1;i++) {
try {
sharedResource.wirte("write thread2_"+i);
Thread.sleep(random.nextInt(100));//随机降低线程执行速度
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
);
read1.start();
read2.start();
write1.start();
write2.start();
}
}
4) 运行结果
Thread name:Thread-1 get readLock //线程1获取到读锁
Thread name:Thread-2 waiting to get writeLock //由于存在读操作,线程2不能获取到写锁只能等待
Thread name:Thread-1 read shared resource:Resource1 //线程1读取共享资源值
Thread name:Thread-3 waiting to get writeLock //由于存在读操作,线程3不能获取到写锁只能等待
Thread name:Thread-0 waiting to get readLock //由于存在等待进行读操作,线程0不能获取到读锁只能等待
Thread name:Thread-1 release readLock //线程1释放读锁,此时没有任何读操作进行, readingThreadNum=0
Thread name:Thread-0 waiting to get readLock //由于存在等待进行读操作,线程0不能获取到读锁只能等待
Thread name:Thread-3 get writeLock //此时没有任何读操作进行,也没有任何写操作进行,线程3获取到写锁
Thread name:Thread-3 set shared resource:write thread2_0 //线程3修改共享资源值
Thread name:Thread-2 waiting to get writeLock //由于线程3进行写操作,线程2不能获取到写锁只能等待
Thread name:Thread-3 release wirteLock //线程3释放写锁 writingThreadNum=0
Thread name:Thread-2 get writeLock //不存在任何读写操作,线程2获取的到写锁
Thread name:Thread-2 set shared resource:write thread1_0 //线程2修改共享资源值
Thread name:Thread-0 waiting to get readLock //线程2进行写操作,线程0获取不到读锁
Thread name:Thread-2 release wirteLock //线程2释放写锁 writingThreadNum=0
Thread name:Thread-0 get readLock //不存在任何读写操作,线程0获取的到读锁
Thread name:Thread-0 read shared resource:write thread1_0 //线程0读取共享资源值
Thread name:Thread-0 release readLock //线程0释放读锁
Thread name:Thread-1 get readLock //线程1获取的到读锁
Thread name:Thread-1 read shared resource:write thread1_0 //线程1读取共享资源值
Thread name:Thread-0 get readLock //线程0获取的到读锁 ,同时读不冲突
Thread name:Thread-0 read shared resource:write thread1_0 //线程0读取共享资源值
Thread name:Thread-1 release readLock //线程1释放读锁
Thread name:Thread-0 release readLock //线程0释放读锁