标签:
和被synchronized修饰的对象同时只能被一个线程访问不同,ReadWriteLock接口提供了更细粒度锁机制。ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持,但是写入锁是独占的。
下面是测试代码:
import org.junit.Test; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockDemo { @Test public void test1() throws InterruptedException { Data data = new Data(); Worker t1 = new Worker(data, true);//读取数据 Worker t2 = new Worker(data, true);//读取数据 t1.start(); t1.join(); t2.start(); t2.join(); } @Test public void test2() throws InterruptedException { Data data = new Data(); Worker t1 = new Worker(data, true);//读取数据 Worker t2 = new Worker(data, false);//设置数据 t1.start(); t1.join(); Thread.sleep(1000); t2.start(); t2.join(); } @Test public void test3() throws InterruptedException { Data data = new Data(); Worker t1 = new Worker(data, false);//设置数据 Worker t2 = new Worker(data, true);//读取数据 t1.start(); t1.join(); Thread.sleep(1000); t2.start(); t2.join(); } @Test public void test4() throws InterruptedException { Data data = new Data(); Worker t1 = new Worker(data, false);//设置数据 Worker t2 = new Worker(data, false);//设置数据 t1.start(); t1.join(); Thread.sleep(1000); t2.start(); t2.join(); } } class Data { static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); ReadWriteLock lock = new ReentrantReadWriteLock(); Lock read = lock.readLock(); Lock write = lock.writeLock(); public void set() { write.lock(); System.out.println(Thread.currentThread().hashCode() + " set:begin " + sdf.format(new Date())); try { Thread.sleep(5000); } catch (Exception e) { } finally { System.out.println(Thread.currentThread().hashCode() + " set:end "+ sdf.format(new Date())); write.unlock(); } } public int get() { read.lock(); System.out.println(Thread.currentThread().hashCode() + " get :begin " + sdf.format(new Date())); try { Thread.sleep(5000); } catch (Exception e) { } finally { System.out.println(Thread.currentThread().hashCode() + " get :end " + sdf.format(new Date())); read.unlock(); } return 1; } } class Worker extends Thread { Data data; boolean read; public Worker(Data data, boolean read) { this.data = data; this.read = read; } public void run() { if (read){ data.get(); } else{ data.set(); } } }
751872434 get :begin 2016-05-04 14:53:49.612 1431398495 get :begin 2016-05-04 14:53:49.613 751872434 get :end 2016-05-04 14:53:54.613 1431398495 get :end 2016-05-04 14:53:54.613 Process finished with exit code 0结果分析:两个线程读取数据的时间是有重合部分的,说明读取锁readLock可以有多个线程同时保持,执行读取锁后,数据还可被其他线程读取。
2034193582 get :begin 2016-05-04 15:03:41.996 2034193582 get :end 2016-05-04 15:03:47.001 1431398495 set:begin 2016-05-04 15:03:48.005 1431398495 set:end 2016-05-04 15:03:53.007 Process finished with exit code 0结果分析:写入数据的线程是在读取数据线程执行完毕之后才执行的,说明读取锁readLock对写入锁writeLock是排斥的,读操作的时候不允许其他线程进行写操作。
751872434 set:begin 2016-05-04 15:11:11.406 751872434 set:end 2016-05-04 15:11:16.409 1402691771 get :begin 2016-05-04 15:11:17.410 1402691771 get :end 2016-05-04 15:11:22.413 Process finished with exit code 0结果分析:读取数据的线程是在写入数据线程执行完毕之后才执行的,说明写入锁writeLock对读取锁readLock是排斥的,写操作的时候不允许其他线程进行读操作。
Run test4() 输出结果如下:
926219290 set:begin 2016-05-04 15:14:53.647 926219290 set:end 2016-05-04 15:14:58.650 2112602078 set:begin 2016-05-04 15:14:59.654 2112602078 set:end 2016-05-04 15:15:04.657 Process finished with exit code 0结果分析:第二个写入数据的线程是在第一个写入数据线程执行完毕之后才执行的,说明写入锁writeLock之间是互斥的,写操作的时候不允许其他线程进行写入操作。
总结:
使用读写锁 ReadWriteLock时,多个读操作是可以并发进行的,但是写操作对数据资源是独占的。
延伸:
在选取读写锁ReadWriteLoc还是同步锁synchronized的抉择中,我们可以通过两个因素来权衡:
1.读取数据的频率相对于写入数据的频率;
2.数据被写入锁定后,等待执行的线程数;
一般地,在需要并发控制的读写操作中,若读取数据频率较高且不是频繁的写入数据的时候,可以考虑使用读写锁以提高并发效率。
标签:
原文地址:http://blog.csdn.net/u011356856/article/details/51313528