类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务。这样做虽然保证了实例变量的线程安全性,但效率却是非常低下的。所以在JDK中提供了一种读写锁ReentrantReadWriteLock类,使用它可以加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁ReentrantReadWriteLock来提升该方法的代码运行速度。
读写锁表示也有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。在没有线程Thread进行写人操作时,进行读取操作的多个Thread都可以获取读锁,而进行写人操作的Thread只有在获取写锁后才能进行写人操作。即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写人操作。
1、读读共享
public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read() { try { lock.readLock().lock(); System.out.println("获得读锁:" +Thread.currentThread().getName() +" " +System.currentTimeMillis()); } finally { lock.readLock().unlock(); } } }
两个自定义线程
public class MyThread1 extends Thread { private Service service; public MyThread1(Service service) { this.service = service; } @Override public void run() { service.read(); } }
public class MyThread2 extends Thread{ private Service service; public MyThread2(Service service) { this.service = service; } @Override public void run() { service.read(); } }
public class Run { public static void main(String[] args) throws InterruptedException { Service service = new Service(); MyThread1 a = new MyThread1(service); a.setName("AA"); a.start(); MyThread2 b = new MyThread2(service); b.setName("BB"); b.start(); } }
获得读锁:AA 1462676138838
获得读锁:BB 1462676138841 |
从控制台中打印的时间来看,两个线程几乎同时进人lock方法后面的代码。说明在此使用了lock.readLock()读锁可以提高程序运行效率,.允许多个线程同时执行locks方法后面的代码。
2、写写互斥
public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void write() { try { lock.writeLock().lock(); System.out.println("获得写锁:" +Thread.currentThread().getName() +" " +System.currentTimeMillis()); } finally { lock.writeLock().unlock(); } } }
上面自定义的线程将read方法改为为write方法。Run类不变,结果如下
获得写锁:BB 1462676627323
获得写锁:AA 1462676627323 |
使用写锁lock.writeLock()的效果就是同一时间只允许一个线程执行lock方法后面的代码
3、读写/写读互斥
public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read() { try { lock.readLock().lock(); System.out.println("获得读锁:" +Thread.currentThread().getName() +" " +System.currentTimeMillis()); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.readLock().unlock(); } } public void write() { try { lock.writeLock().lock(); System.out.println("获得写锁:" +Thread.currentThread().getName() +" " +System.currentTimeMillis()); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.writeLock().unlock(); } } }
自定义的线程MyThread1里的run为read方法,MyThread2里的run方法为write.
获得写锁:BB 1462677688372
获得读锁:AA 1462677691372 |
说明‘“读写”是互斥的
“读写”“、”写读“、”写写“都是互斥的;而”读读“是异步的,非互斥的