目录
一、ReentrantLock可重入锁
二、ReentrantReadWriteLock读写锁
三、读锁之间不互斥

一、ReentrantLock可重入锁
可重入锁ReentrantLock 是一个互斥锁,即同一时间只有一个线程可能获取锁定资源,执行锁定范畴内的代码。这一点与synchronized 关键字十分相似。其根本用法代码如下:

Lock lock = new ReentrantLock();  //实例化锁//lock.lock(); //上锁boolean locked = lock.tryLock();  //尝试上锁if(locked){  try {    //被锁定的同步代码块,同时只能被一个线程执行  }finally {    lock.unlock(); //放在finally代码块中,保障锁肯定会被开释  }}

通过lock函数获取锁,通过unlock函数开释锁。十分重要的是,须要把须要同步执行的代码放入 try/finally 代码块中,并在finally中将锁开释。ReentrantLock是可重入锁,即:(lock/unlok)动作外面能够嵌套(lock/unlock),针对同一个锁能够屡次嵌套应用,不会产生死锁。然而lock函数与unlock函数在代码中必须成对呈现,否则会呈现死锁。

二、ReentrantReadWriteLock读写锁
ReentrantReadWriteLock类为读写锁实现类,针对某一个对象或可变变量,只有没有线程在批改它,这个对象或可变变量就能够同时被多个线程读取。ReentrantReadWriteLock将锁分为读锁和写锁,只有没有线程持有写锁的状况下,读锁能够由多个线程同时持有。

读锁-如果没有线程获取或申请写锁,那么多个线程能够获取读锁
写锁-如果没有线程在读或写,那么只有一个线程能够取得写锁
简略的说就是ReentrantReadWriteLock能够保障最多同时有一个线程在写数据,或者能够同时有多个线程读数据。因而应用ReentrantReadWriteLock,在读操作比写操作更频繁的状况下,能够进步程序的性能和吞吐量。

Java技术迷

上面咱们用一个简略的例子,来解读一下如何利用读写锁。

public class TestReadWriteLock {  //能够同时执行3个线程工作的线程池  ExecutorService executor = Executors.newFixedThreadPool(3);  //读写指标,写线程放入数据到map,读线程从map读取数据  Map<String, String> map = new HashMap<>();  //读写锁操作对象  ReadWriteLock lock = new ReentrantReadWriteLock();   //写操作函数  public void write(){    executor.submit(() -> { //线程池提交写操作工作      lock.writeLock().lock(); //加写锁      try {        map.put("key", "val");  //写数据操作        Thread.sleep(2000);      } catch (InterruptedException e) {        e.printStackTrace();      } finally {        lock.writeLock().unlock(); //开释写锁      }    });  }   //读操作函数  public void read(){    lock.readLock().lock(); //加读锁    System.out.println(Thread.currentThread().getName() + "加读锁");    try {      System.out.println(map.get("key")); //读数据操作    } finally {      lock.readLock().unlock(); //开释读锁      System.out.println(Thread.currentThread().getName() + "开释读锁");    }  } }

三、读锁之间不互斥
咱们写一个测试方法,通过打印输出来了解读写锁控制代码的执行程序。

//测试public static void main(String[] args) {  TestReadWriteLock test = new TestReadWriteLock();  test.write();  //提交一次写操作工作,写一条数据  Runnable readTask = test::read;  //线程办法read,实现线程Runnable接口的简便写法  test.executor.submit(readTask);  //读1次(新读线程)  test.executor.submit(readTask);  //读2次 (新读线程)  test.executor.shutdown();}

执行下面的代码,可能会呈现上面的输入

pool-1-thread-2加读锁
pool-1-thread-3加读锁
val
val
pool-1-thread-3开释读锁
pool-1-thread-2开释读锁

在pool-1-thread-2没有开释读锁状况下,pool-1-thread-3能够再次加读锁,并且都正确的读取到数据val。阐明读锁之间是不互斥的。然而,在进行读操作(读锁失效)的时候,写操作是无奈进行的(无奈获取写锁),所以ReentrantReadWriteLock不反对同时加读锁和写锁。 这个论断我能够负责任通知大家,这里我就不做验证了!