`

读写锁小总结

    博客分类:
  • java
阅读更多

今天小组组织了一次java性能培训,提到了读写锁,以前没有关注过这个东西,于是培训结束后写个程序探索一下读写锁的使用方式。

 

final ReadWriteLock lock = new ReentrantReadWriteLock();

ReadWriteLock具有两把锁,lock.readLock()和lock.writeLock(),特性总结如下:

1、readLock与readLock之间不是互斥的,可以并发执行。实验代码如下:

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Main
{
   public static void main(String[] args)
   {
      final ReadWriteLock lock = new ReentrantReadWriteLock();
      new Thread(new Runnable()
      {

          @Override
          public void run()
          {

              lock.readLock().lock();
              System.out.println(Thread.currentThread().getName() + ":Sleep begin.");
              // 休眠5秒
              sleepInSeconds(5);
              System.out.println(Thread.currentThread().getName()+ ":Sleep complete.");
              lock.readLock().unlock();

           }
       }, "Thread-1").start();

 

      //此处休眠1秒,确保上面的代码得以先执行
      sleepInSeconds(1);

 

      new Thread(new Runnable()
      {

          @Override
          public void run()
         {
             lock.readLock().lock();
             System.out.println(Thread.currentThread().getName()+ ":Sleep begin.");
             // 休眠2秒
             sleepInSeconds(2);
             System.out.println(Thread.currentThread().getName() + ":Sleep complete.");
             lock.readLock().unlock();
        }
     }, "Thread-2").start();
 }

   /**
    * 休眠一定时间,单位5秒
    * @param seconds 要休眠的秒数
    */
    private static void sleepInSeconds(int seconds)
    {
        try
        {
            Thread.sleep(seconds * 1000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
     }

}

Thread-1:Sleep begin.
Thread-2:Sleep begin.
Thread-2:Sleep complete.
Thread-1:Sleep complete.

 

根据输出可以看出,虽然Thread-1已经调用了,lock.readLock().lock(),但是Thread-2还是在Thread-1调用lock.readLock().unlock()之前就执行打印了,说明两个readLock之间是互不影响的。

 

2、readLock和writeLock是互斥的,实验代码如下:

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Main
{
   public static void main(String[] args)
   {
      final ReadWriteLock lock = new ReentrantReadWriteLock();
      new Thread(new Runnable()
      {

          @Override
          public void run()
          {

              lock.readLock().lock();
              System.out.println(Thread.currentThread().getName() + ":Sleep begin.");
              // 休眠5秒
              sleepInSeconds(5);
              System.out.println(Thread.currentThread().getName()+ ":Sleep complete.");
              lock.readLock().unlock();

           }
       }, "Thread-1").start();

 

      //此处休眠1秒,确保上面的代码得以先执行
      sleepInSeconds(1);

 

      new Thread(new Runnable()
      {

          @Override
          public void run()
         {
             lock.writeLock().lock();
             System.out.println(Thread.currentThread().getName()+ ":Sleep begin.");
             // 休眠2秒
             sleepInSeconds(2);
             System.out.println(Thread.currentThread().getName() + ":Sleep complete.");
             lock.writeLock().unlock();
        }
     }, "Thread-2").start();
 }

   /**
    * 休眠一定时间,单位5秒
    * @param seconds 要休眠的秒数
    */
    private static void sleepInSeconds(int seconds)
    {
        try
        {
            Thread.sleep(seconds * 1000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
     }

}

Thread-1:Sleep begin.
Thread-1:Sleep complete.

Thread-2:Sleep begin.
Thread-2:Sleep complete.

 

3、writeLock与writeLock之间是互斥的,实验代码如下

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Main
{
   public static void main(String[] args)
   {
      final ReadWriteLock lock = new ReentrantReadWriteLock();
      new Thread(new Runnable()
      {

          @Override
          public void run()
          {

              lock.writeLock().lock();
              System.out.println(Thread.currentThread().getName() + ":Sleep begin.");
              // 休眠5秒
              sleepInSeconds(5);
              System.out.println(Thread.currentThread().getName()+ ":Sleep complete.");
              lock.writeLock().unlock();

           }
       }, "Thread-1").start();

 

      //此处休眠1秒,确保上面的代码得以先执行
      sleepInSeconds(1);

 

      new Thread(new Runnable()
      {

          @Override
          public void run()
         {
             lock.writeLock().lock();
             System.out.println(Thread.currentThread().getName()+ ":Sleep begin.");
             // 休眠2秒
             sleepInSeconds(2);
             System.out.println(Thread.currentThread().getName() + ":Sleep complete.");
             lock.writeLock().unlock();
        }
     }, "Thread-2").start();
 }

   /**
    * 休眠一定时间,单位5秒
    * @param seconds 要休眠的秒数
    */
    private static void sleepInSeconds(int seconds)
    {
        try
        {
            Thread.sleep(seconds * 1000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
     }

}

Thread-1:Sleep begin.
Thread-1:Sleep complete.

Thread-2:Sleep begin.
Thread-2:Sleep complete.

 

由于readLock与writeLock是互斥的,而readLock与readLock之间是非互斥的,产生了一种猜想,假设有这么一种场景:

Thread-1在第0秒的时候执行了readLock().lock()

Thread-1在第5秒的时候执行了readLock().unlock()

 

Thread-2在第2秒的时候执行了writeLock().lock()

Thread-2在第7秒的时候执行了writeLock().unlock()

 

Thread-3在第4秒的时候执行了writeLock().lock()

Thread-3在第9秒的时候执行了writeLock().unlock()

 

由于Thread-2的writeLock与Thread-1的readLock是互斥的,所以在第5秒之前Thread-2的writeLock之间的代码都不会执行,但Thread-1和Thread-3都是读锁,会不会出现Thread-3的readLock之间的代码先于Thread-2的writeLock之间的代码执行的情况,做个实验便知

 

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Main
{
 private static long beginTime;
 public static void main(String[] args)
 {
  final ReadWriteLock lock = new ReentrantReadWriteLock();
  beginTime = System.currentTimeMillis();
  new Thread(new Runnable()
  {

   @Override
   public void run()
   {
    System.out.println(Thread.currentThread().getName()+ " begin running."+getTime());
    lock.writeLock().lock();
    System.out.println(Thread.currentThread().getName()+ ":Sleep begin."+getTime());
    // 休眠5秒
    sleepInSeconds(5);
    System.out.println(Thread.currentThread().getName()+ ":Sleep complete."+getTime());
    lock.writeLock().unlock();

   }
  }, "Thread-1").start();
  
  //此处休眠1秒,确保上面的代码得以先执行
  sleepInSeconds(2);

  new Thread(new Runnable()
  {

   @Override
   public void run()
   {
    System.out.println(Thread.currentThread().getName()+ " begin running."+getTime());
    lock.writeLock().lock();
    System.out.println(Thread.currentThread().getName()+ ":Sleep begin."+getTime());
    // 休眠2秒
    sleepInSeconds(5);
    System.out.println(Thread.currentThread().getName()+ ":Sleep complete."+getTime());
    lock.writeLock().unlock();
   }
  }, "Thread-2").start();
  
  //此处休眠1秒,确保上面的代码得以先执行
  sleepInSeconds(2);

  new Thread(new Runnable()
  {

   @Override
   public void run()
   {
    System.out.println(Thread.currentThread().getName()+ " begin running."+getTime());
    lock.readLock().lock();
    System.out.println(Thread.currentThread().getName()+ ":Sleep begin."+getTime());
    // 休眠2秒
    sleepInSeconds(5);
    System.out.println(Thread.currentThread().getName()+ ":Sleep complete."+getTime());
    lock.readLock().unlock();
   }
  }, "Thread-3").start();
 }

 /**
  * 休眠一定时间,单位5秒
  * @param seconds 要休眠的秒数
  */
 private static void sleepInSeconds(int seconds)
 {
  try
  {
   Thread.sleep(seconds * 1000);
  }
  catch (InterruptedException e)
  {
   e.printStackTrace();
  }
 }
 
 /**
  * 获取时间字符串
  * @return
  */
 private static String getTime()
 {
  return " Time:"+(System.currentTimeMillis() - beginTime)/1000;
 }

}

Thread-1 begin running. Time:0
Thread-1:Sleep begin. Time:0
Thread-2 begin running. Time:2
Thread-3 begin running. Time:4
Thread-1:Sleep complete. Time:5
Thread-2:Sleep begin. Time:5
Thread-2:Sleep complete. Time:10
Thread-3:Sleep begin. Time:10
Thread-3:Sleep complete. Time:15

 

 

从实验结果来看,Thread-1,Thread-2,Thread-3的代码已经按照原先设计在分别在0秒,2秒,4秒的时刻被调用,但是其lock部分的代码却是:Thread-1的lock代码先执行,Thread-1执行完了才执行Thread-2的lock代码,Thread-2执行完了才执行Thread-3的lock代码。

 

之前猜想的Thread-3的lock代码先于Thread-2的lock代码执行的情况没有出现,也就是说虽然当前正在执行的代码是readLock的代码,但如果存在一个writeLock排队,那么其它readLock是无法与当前正在执行的readLock并行执行的。

 

欢迎拍砖

分享到:
评论

相关推荐

    面试官:有没有比读写锁更快的锁?

    目录面试三连什么是读写锁StampedLock横空出世StampedLock三种模式基本语法StampedLock完整的demo让StampedLock性能更上一楼的乐观读你了解乐观读的应用场景吗使用StampedLock的注意事项总结 面试三连 面试官:了解...

    asp.net 细说文件读写操作(读写锁)

    开发过程中,我们玩玩需要大量与文件交互,读文件,写文件已成家常便饭,本地运行完美,但一上到投产环境,往往会出现很多令人措手不及的意外,或开发中的烦恼,因此,我对普通的C#文件操作做了一次总结

    Linux系统编程-(pthread)线程通信(条件变量).pdf

    **读写锁总结:** 1. 读写锁分为读锁和写锁。 2. 如果资源被读写锁保护,多个线程可以同时获取读锁—也就是读支持多个线程同时读。 3. 资源加了写锁之后,在写资源的时候只能被一个线程占用,其他读锁就会阻塞。 ...

    FileShare枚举的使用小结(文件读写锁)

    开发过程中,我们往往需要大量与文件交互,读文件,写文件已成家常便饭,本地运行完美,但一上到投产环境,往往会出现很多令人措手不及的意外,或开发中的烦恼,因此,我对普通的C#文件操作做了一次总结,问题大部分...

    python互斥锁、加锁、同步机制、异步通信知识总结

    互斥锁保证了每次只有一个线程进入写入操作,从而保证了多线程情况下数据的正确性。 采用f_flag的方法效率低 创建锁 mutex=threading.Lock() 锁定 mutex.acquire([blocking])#里面可以加blocking(等待的时间)或者...

    android安卓app开发教程之--总结了50条安卓开发经验.zip

    (123代表不同线程,轮流插入一个记录),读和写均不会锁住db,读写交替并没有规律,执行次数和程度看cpu分配给哪个线程的时间片长 43. 选择正确的集合类型使你能够在集合性能与内存占用之间达到合理的平衡。除此...

    多线程性能测试总结文档

    1、单线程加锁读写全局数据,每秒读多少次?建议使用读XXX万次,用多少时间来计算。 2、多线程加锁读写全局...3、每个线程每秒只读500次并且读后不要立即释放锁的情况下(执行一段for循环代码),执行2与2.1两个步骤

    InnoDB怎么应对高并发

    (2)普通锁串行,读写锁读读并行,数据多版本读写并行; (3)redo日志保证已提交事务的ACID特性,设计思路是,通过顺序写替代随机写,提高并发; (4)undo日志用来回滚未提交的事务,它存储在回滚段里; (5)InnoDB是...

    go语言开发技巧入门教程总结.docx

    解决方案:使用互斥锁(sync.Mutex)、读写锁(sync.RWMutex)或channels进行同步;使用原子操作(sync/atomic包);遵循最小权限原则,尽量减少共享数据。 错误处理 问题描述:错误处理代码冗余,影响可读性。 解决方案...

    最新单片机课程设计电子密码锁设计通信班-免费下载.doc

    9 2.3.4 修改密码程序 10 2.3.5 LCD显示程序 11 2.4 仿真测试结果 12 3 总结 14 参考文献 15 附录 16 1 引言 随着科技和人们的生活水平的提高,如何实现家庭防盗这一问题也变的尤其的突出, 传统机械锁由于构造简单...

    关于GD32芯片读保护的描述和解决办法1.pdf

    该文档总结arm芯片,内部flash写保护的解决的一般通用方法,适用于stm32,gd32系列芯片,具体请查看文档内容

    C#多线程编程中的锁系统(二)

    4:总结 一:volatile 简单来说: volatile关键字是告诉c#编译器和JIT编译器,不对volatile标记的字段做任何的缓存。确保字段读写都是原子操作,最新值。 这不就是锁吗? 其这货它根本不是锁, 它的原子操作是基于...

    SQL 数据库性能调优方面的总结

    将数据均匀分布在磁盘上可以提高i/o利用率,提高数据的读写性能;适当程度的非规范化可以改善系统查询性能;建立索引和编写高效的sql语句能有效避免低性能操作;通过锁的调优解决并发控制方面的性能问题。数据库调优...

    【2018最新最详细】并发多线程教程

    11.深入理解读写锁ReentrantReadWriteLock 12.详解Condition的await和signal等待通知机制 13.LockSupport工具 14.并发容器之ConcurrentHashMap(JDK 1.8版本) 15.并发容器之ConcurrentLinkedQueue 16.并发容器之...

    深入理解Java源码:提升技术功底,深度掌握技术框架,快速定位线上问题

    并发优化包括volatile的大量、正确使用,CAS和原子类的广泛使用,线程安全容器的使用,以及通过读写锁提升并发性能等。 总的来说,Java源码的学习和理解是提升技术功底,深度掌握技术框架,快速定位

    2019 年终总结,240+篇,已分类整理

    code小生 一个专注大前端领域的技术平台 ...以下内容按照技术模块来划分,每个大的分类下文章顺序是按照难易程序来的,这样学习起来方便些。...Android 读写锁的应用,以及最佳的磁盘缓存设计 RxJava2

    Java并发编程原理与实战

    读写锁认识与原理.mp4 细读ReentrantReadWriteLock源码.mp4 ReentrantReadWriteLock锁降级详解.mp4 线程安全性问题简单总结.mp4 线程之间的通信之wait notify.mp4 通过生产者消费者模型理解等待唤醒机制.mp4 ...

    python学习应用手册(上册)

    1、pycharm环境安装与使用、常用快捷键、操作指南 2、详尽的基本的数据类型讲解,配套现成代码:字符串、数字、列表、元组、字典、集合...12、进程、线程、协程、互斥锁、递归锁、升序锁、yield表达式、async/await异步

    Android开发性能优化总结

    一. 加载 预加载:1.反射注解框架Reflect信息,在Application内多线程预加载至缓存。...2. 并发操作多用读写锁,少用synchronized,Android虚拟机Art直到Android6.0为止尚未对synchronized做CAS优化,而sy

    [14本经典Android开发教程]-8-Linux内核阅读心得体会

    [14本经典Android开发教程] 8 Linux内核阅读心得体会 读核感悟 2 读核感悟 Linux内核启动 内核的生成 2 读核感悟 Linux内核启动 从hello world说起 3 ...读核感悟 文件读写 内核态是否支持非direct I O方式的AIO ...

Global site tag (gtag.js) - Google Analytics