类ReentranLock具有万川互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务。这样虽然保证了实例变量的线程安全性,
但效率却是非常低下的。所以在jdk中提供了一种读写锁ReentrantReadWriteLock类,使它可以加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁
ReentrantReadWriteLock来提升该方法的代码运行速度。
读写锁表示也有两个锁,一个是读操作相关的锁,也称为共享锁;另一个事写操作相关的做,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。
在没有现成Thread进行写入操作时,进行读取操作的多个Thread都可以获取读锁,而进行写入操作的Thread只有在获取写锁后才能进行写入操作。即多个Thread可以同时进行读取操作,但是同一时刻,只允许一个Thread进行写入操作。
读读共享:
Service类:
package ReadAndWriteLock; import java.io.BufferedWriter; import java.time.LocalDate; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class Service { private ReentrantReadWriteLock lock=new ReentrantReadWriteLock(); public void read(){ try { try { lock.readLock().lock();; System.out.println("线程 : "+Thread.currentThread().getName()+" 时间: "+System.currentTimeMillis()+" 获得锁"); Thread.sleep(10000); } finally { lock.readLock().unlock(); } } catch (Exception e) { e.printStackTrace(); } } }
主方法:
package ReadAndWriteLock; public class Run { public static void main(String[] args) { final Service service=new Service(); new Thread(new Runnable() { public void run() { service.read(); } }).start(); new Thread(new Runnable() { public void run() { service.read(); } }).start(); } }
控制台:
线程 : Thread-0 时间: 1534585340658 获得锁 线程 : Thread-1 时间: 1534585340659 获得锁
可以发现,两个线程几乎同时进入了lock方法后面的代码,说明在此使用读写锁可以提供程序运行效率,允许多个线程同时制定lock()方法后面的代码。
写写互斥:
Service类
public class Service1 { private ReentrantReadWriteLock lock=new ReentrantReadWriteLock(); public void write() { try { try { lock.writeLock().lock();; System.out.println("线程: "+Thread.currentThread().getName()+" 时间: "+System.currentTimeMillis()+" 获得锁"); Thread.sleep(10000); } finally { lock.writeLock().unlock(); } } catch (Exception e) { e.printStackTrace(); } } }
主线程:
public class Run { public static void main(String[] args) { final Service1 service1=new Service1(); new Thread(new Runnable() { public void run() { service1.write(); } }).start(); new Thread(new Runnable() { public void run() { service1.write(); } }).start(); } }
控制台:
线程: Thread-0 时间: 1534585587952 获得锁 线程: Thread-1 时间: 1534585597955 获得锁
使用写锁代码lock.writeLock()的效果就是同意时间只允许一个线程执行lock()方法后面的代码。
写读互斥:
service2类
public class Service2 { private ReentrantReadWriteLock lock=new ReentrantReadWriteLock(); public void read() { try { try { lock.readLock().lock(); System.out.println("线程: "+Thread.currentThread().getName()+" 时间: "+System.currentTimeMillis()); Thread.sleep(10000); } finally { lock.readLock().unlock(); } } catch (Exception e) { e.printStackTrace(); } } public void write() { try { try { lock.writeLock().lock(); System.out.println("线程: "+Thread.currentThread().getName()+" 时间: "+System.currentTimeMillis()); Thread.sleep(10000); } finally { lock.writeLock().unlock(); } } catch (Exception e) { e.printStackTrace(); } } }
主线程:
public class Run { public static void main(String[] args) { final Service2 service2=new Service2(); new Thread(new Runnable() { public void run() { service2.write(); } }).start(); new Thread(new Runnable() { public void run() { service2.read(); } }).start(); } }
控制台:
线程: Thread-0 时间: 1534586198910 线程: Thread-1 时间: 1534586208910
从时间上看,写读操作是互斥的。
读写互斥:
将主线程中的方法改为如下:
public class Run { public static void main(String[] args) throws InterruptedException { final Service2 service2=new Service2(); new Thread(new Runnable() { public void run() { service2.read(); } }).start(); Thread.sleep(1000); new Thread(new Runnable() { public void run() { service2.write(); } }).start(); } }
控制台:
线程: Thread-0 时间: 1534586426809 线程: Thread-1 时间: 1534586436810
读写操作也是互斥的。
结论: 读写,写读,写写都是互斥的:而读读是异步的,非互斥的。
每一个优秀的人,都有一段沉默的时光。不抱怨,不诉苦,最后度过那段感动自己的日子。