当前位置:   article > 正文

ReentrantReadWriteLock读写锁的使用_reentrantreadwritelock.writelock[]

reentrantreadwritelock.writelock[]

类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()后面的代码。这样虽然保证了线程的安全性,但是效率低下。JDK提供了ReentrantReadWriteLock读写锁,使用它可以加快效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁ReemtrantReadWriteLock来提升该方法的运行速度。

  读写锁表示有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁互斥、写锁与写锁互斥。在没有线程Thread进行写入操作时,进行读取操作的多个Thread都可以获取读锁,而进行写入操作的Thread只有在获取写锁后才能进行写入操作。即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。
 

1.读读共享

  读锁与读锁可以共享,这种锁一般用于只读操作,不对变量进行修改操作。

  1. package cn.qlq.thread.twelve;
  2. import java.util.concurrent.locks.ReentrantReadWriteLock;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import cn.qlq.thread.one.RunnableThread;
  6. public class Demo1 {
  7. private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
  8. private static final Logger log = LoggerFactory.getLogger(Demo1.class);
  9. private int i;
  10. public String readI() {
  11. try {
  12. lock.readLock().lock();// 占用读锁
  13. log.info("threadName -> {} 占用读锁,i->{}", Thread.currentThread().getName(), i);
  14. Thread.sleep(2 * 1000);
  15. } catch (InterruptedException e) {
  16. } finally {
  17. log.info("threadName -> {} 释放读锁,i->{}", Thread.currentThread().getName(), i);
  18. lock.readLock().unlock();// 释放读锁
  19. }
  20. return i + "";
  21. }
  22. public static void main(String[] args) {
  23. final Demo1 demo1 = new Demo1();
  24. Runnable runnable = new Runnable() {
  25. @Override
  26. public void run() {
  27. demo1.readI();
  28. }
  29. };
  30. new Thread(runnable, "t1").start();
  31. new Thread(runnable, "t2").start();
  32. new Thread(runnable, "t3").start();
  33. }
  34. }

 

结果:

18:27:20 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t2 占用读锁,i->0
18:27:20 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t1 占用读锁,i->0
18:27:20 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t3 占用读锁,i->0
18:27:22 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t3 释放读锁,i->0
18:27:22 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t1 释放读锁,i->0
18:27:22 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t2 释放读锁,i->0

 

2.写写互斥

  写锁与写锁互斥,这就类似于ReentrantLock的作用效果。

 
  1. package cn.qlq.thread.twelve;
  2. import java.util.concurrent.locks.ReentrantReadWriteLock;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. public class Demo2 {
  6. private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
  7. private static final Logger log = LoggerFactory.getLogger(Demo2.class);
  8. private int i;
  9. public void addI() {
  10. try {
  11. lock.writeLock().lock();// 占用写锁
  12. log.info("threadName -> {} 占用写锁,i->{}", Thread.currentThread().getName(), i);
  13. Thread.sleep(2 * 1000);
  14. i++;
  15. } catch (InterruptedException e) {
  16. } finally {
  17. log.info("threadName -> {} 释放写锁,i->{}", Thread.currentThread().getName(), i);
  18. lock.writeLock().unlock();// 释放写锁
  19. }
  20. }
  21. public static void main(String[] args) {
  22. final Demo2 demo1 = new Demo2();
  23. Runnable runnable = new Runnable() {
  24. @Override
  25. public void run() {
  26. demo1.addI();
  27. }
  28. };
  29. new Thread(runnable, "t1").start();
  30. new Thread(runnable, "t2").start();
  31. new Thread(runnable, "t3").start();
  32. }
  33. }

 

结果:(从时间可以看出实现了互斥效果)

18:31:31 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t1 占用写锁,i->0
18:31:33 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t1 释放写锁,i->1
18:31:33 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t2 占用写锁,i->1
18:31:35 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t2 释放写锁,i->2
18:31:35 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t3 占用写锁,i->2
18:31:37 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t3 释放写锁,i->3

3.读写互斥

  1. package cn.qlq.thread.twelve;
  2. import java.util.concurrent.locks.ReentrantReadWriteLock;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. /**
  6. * 读写互斥
  7. *
  8. * @author Administrator
  9. *
  10. */
  11. public class Demo3 {
  12. private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
  13. private static final Logger log = LoggerFactory.getLogger(Demo3.class);
  14. private int i;
  15. public String readI() {
  16. try {
  17. lock.readLock().lock();// 占用读锁
  18. log.info("threadName -> {} 占用读锁,i->{}", Thread.currentThread().getName(), i);
  19. Thread.sleep(2 * 1000);
  20. } catch (InterruptedException e) {
  21. } finally {
  22. log.info("threadName -> {} 释放读锁,i->{}", Thread.currentThread().getName(), i);
  23. lock.readLock().unlock();// 释放读锁
  24. }
  25. return i + "";
  26. }
  27. public void addI() {
  28. try {
  29. lock.writeLock().lock();// 占用写锁
  30. log.info("threadName -> {} 占用写锁,i->{}", Thread.currentThread().getName(), i);
  31. Thread.sleep(2 * 1000);
  32. i++;
  33. } catch (InterruptedException e) {
  34. } finally {
  35. log.info("threadName -> {} 释放写锁,i->{}", Thread.currentThread().getName(), i);
  36. lock.writeLock().unlock();// 释放写锁
  37. }
  38. }
  39. public static void main(String[] args) throws InterruptedException {
  40. final Demo3 demo1 = new Demo3();
  41. new Thread(new Runnable() {
  42. @Override
  43. public void run() {
  44. demo1.readI();
  45. }
  46. }, "t1").start();
  47. Thread.sleep(1 * 1000);
  48. new Thread(new Runnable() {
  49. @Override
  50. public void run() {
  51. demo1.addI();
  52. }
  53. }, "t2").start();
  54. }
  55. }

结果:

18:34:59 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 占用读锁,i->0
18:35:01 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 释放读锁,i->0
18:35:01 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 占用写锁,i->0
18:35:03 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 释放写锁,i->1

 

4.写读互斥

  写锁与读锁也是互斥的。先占用写锁后读锁进行抢占也会等待写锁释放。

  1. package cn.qlq.thread.twelve;
  2. import java.util.concurrent.locks.ReentrantReadWriteLock;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. /**
  6. * 读写互斥
  7. *
  8. * @author Administrator
  9. *
  10. */
  11. public class Demo3 {
  12. private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
  13. private static final Logger log = LoggerFactory.getLogger(Demo3.class);
  14. private int i;
  15. public String readI() {
  16. try {
  17. lock.readLock().lock();// 占用读锁
  18. log.info("threadName -> {} 占用读锁,i->{}", Thread.currentThread().getName(), i);
  19. Thread.sleep(2 * 1000);
  20. } catch (InterruptedException e) {
  21. } finally {
  22. log.info("threadName -> {} 释放读锁,i->{}", Thread.currentThread().getName(), i);
  23. lock.readLock().unlock();// 释放读锁
  24. }
  25. return i + "";
  26. }
  27. public void addI() {
  28. try {
  29. lock.writeLock().lock();// 占用写锁
  30. log.info("threadName -> {} 占用写锁,i->{}", Thread.currentThread().getName(), i);
  31. Thread.sleep(2 * 1000);
  32. i++;
  33. } catch (InterruptedException e) {
  34. } finally {
  35. log.info("threadName -> {} 释放写锁,i->{}", Thread.currentThread().getName(), i);
  36. lock.writeLock().unlock();// 释放写锁
  37. }
  38. }
  39. public static void main(String[] args) throws InterruptedException {
  40. final Demo3 demo1 = new Demo3();
  41. new Thread(new Runnable() {
  42. @Override
  43. public void run() {
  44. demo1.addI();
  45. }
  46. }, "t2").start();
  47. Thread.sleep(1 * 1000);
  48. new Thread(new Runnable() {
  49. @Override
  50. public void run() {
  51. demo1.readI();
  52. }
  53. }, "t1").start();
  54. }
  55. }
 

 

结果:

18:36:14 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 占用写锁,i->0
18:36:16 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 释放写锁,i->1
18:36:16 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 占用读锁,i->1
18:36:18 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 释放读锁,i->1

 

总结: 读写、写读、写写都是互斥的,而读读是异步非互斥的。

      也就是只要有写锁的参与就会进行同步,所以写锁也被称为排他锁,读锁被称为共享锁。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/956085
推荐阅读
相关标签
  

闽ICP备14008679号