Java并发编程之重入锁与读写锁

发布时间 - 2026-01-11 03:24:28    点击率:

重入锁

重入锁,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁。重进入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁阻塞,该特性的实现需要解决以下两个问题。

1、线程再次获取锁。锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取。

2、锁的最终释放。线程重复n次获取了锁,随后在第n次释放该锁后,其他线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时表示锁已经成功释放。

Java里面内置锁(synchronize)和Lock(ReentrantLock)都是可重入的

synchronized 实例

package com.home;
public class SynchronizedTest implements Runnable {
  public synchronized void method1() {
    System.out.println("method1获得锁,正常运行!");
    method2();
  }
  public synchronized void method2() {
    System.out.println("method2获得锁,也正常运行!");
  }
  @Override
  public void run() {
    method1();
  }
  public static void main(String[] args) {
    SynchronizedTest st = new SynchronizedTest();
    new Thread(st).start();
    new Thread(st).start();
  }
}

Lock 实例

package com.home;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest implements Runnable {
  Lock lock = new ReentrantLock();
  public void method1() {
    lock.lock();
    System.out.println("method1获得锁,正常运行!");
    method2();
    lock.unlock();
  }
  public void method2() {
    lock.lock();
    System.out.println("method2获得锁,也正常运行!");
    lock.unlock();
  }
  @Override
  public void run() {
    method1();
  }
  public static void main(String[] args) {
    LockTest lt = new LockTest();
    new Thread(lt).start();
    new Thread(lt).start();
  }
}

两个例子最后的结果都是正确的,结果如下:

method1获得锁,正常运行!
method2获得锁,也正常运行!
method1获得锁,正常运行!
method2获得锁,也正常运行!

可重入锁最大的作用是避免死锁

读写锁

读写锁维护了一对相关的锁,一个用于只读操作,一个用于写入操作。只要没有writer,读取锁可以由多个reader线程同时保持。写入锁是独占的。

可重入读写锁 ReentrantReadWriteLock

ReentrantReadWriteLock对象提供了readLock()和writeLock()方法, 用于获取读取锁和写入锁.

读取锁允许多个reader线程同时持有, 而写入锁最多只能有一个writter线程持有.

读写锁的使用场合: 读取共享数据的频率远大于修改共享数据的频率. 在上述场合下, 使用读写锁控制共享资源的访问, 可以提高并发性能.

如果一个线程已经持有了写入锁, 则可以再持有读写锁. 相反, 如果一个线程已经持有了读取锁, 则在释放该读取锁之前, 不能再持有写入锁.

可以调用写入锁的newCondition()方法获取与该写入锁绑定的Condition对象, 此时与普通的互斥锁并没有什么区别. 但是调用读取锁的newCondition()方法将抛出异常.

例子

package com.home;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class ReadWrte {
  // 共享数据,可以多个线程读数据,只能有一个线程写数据
  private int data;
  // 创建读写锁
  ReadWriteLock rwLock = new ReentrantReadWriteLock();
  /**
   * 读数据,上读锁
   */
  public void get() {
    // 读锁
    rwLock.readLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + ",Read!");
      Thread.sleep((long) Math.random() * 1000);
      System.out.println(Thread.currentThread().getName() + " 读出的数据为:" +
        this.getData());
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      rwLock.readLock().unlock();
    }
  }
  /**
   * 写数据,上写锁
   *
   * @param data
   */
  public void put(int data) {
    // 写锁
    rwLock.writeLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + ",Write!");
      Thread.sleep((long) Math.random() * 1000);
      this.setData(data);
      System.out.println(Thread.currentThread().getName() + " 写入的数据为:" +
        this.getData());
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      rwLock.writeLock().unlock();
    }
  }
  public int getData() {
    return data;
  }
  public void setData(int data) {
    this.data = data;
  }
}
/**
 * 测试类
 *
 * @author itmyhome
 *
 */
public class ReadWriteLockTest {
  /**
   * @param args
   */
  public static void main(String[] args) {
    // 创建ReadWrte对象
    final ReadWrte rw = new ReadWrte();
    for (int i = 0; i < 10; i++) {
      // 创建并启动10个读线程
      new Thread(new Runnable() {
          @Override
          public void run() {
            rw.get();
          }
        }).start();
      // 创建并启动10个写线程
      new Thread(new Runnable() {
          @Override
          public void run() {
            // 写入一个随机数
            rw.put(new Random().nextInt(8));
          }
        }).start();
    }
  }
}

输出为

Thread-0,Read!
Thread-4,Read!
Thread-8,Read!
Thread-12,Read!
Thread-0 读出的数据为:0
Thread-4 读出的数据为:0
Thread-8 读出的数据为:0
Thread-12 读出的数据为:0
Thread-19,Write!
Thread-19 写入的数据为:5
Thread-7,Write!
Thread-7 写入的数据为:7
Thread-3,Write!
Thread-3 写入的数据为:4
Thread-16,Read!
Thread-16 读出的数据为:4
Thread-11,Write!
Thread-11 写入的数据为:0
Thread-15,Write!
Thread-15 写入的数据为:5
Thread-2,Read!
Thread-2 读出的数据为:5
Thread-17,Write!
Thread-17 写入的数据为:2
Thread-6,Read!
Thread-6 读出的数据为:2
Thread-1,Write!
Thread-1 写入的数据为:5
Thread-13,Write!
Thread-13 写入的数据为:4
Thread-9,Write!
Thread-9 写入的数据为:7
Thread-5,Write!
Thread-5 写入的数据为:2
Thread-10,Read!
Thread-10 读出的数据为:2
Thread-18,Read!
Thread-14,Read!
Thread-18 读出的数据为:2
Thread-14 读出的数据为:2

从图中我们可以看出,可以多个线程同时读,但只能一个线程写,即写数据和写入数据一并完成。

总结

以上就是本文关于Java并发编程之重入锁与读写锁的全部内容,希望对大家有所帮助。欢迎各位参阅本站其他专题,有什么问题可以随时留言,小编会及时回复大家的。感谢大家对本站的支持。


# java  # 读写锁  # 编程实现读写锁  # 无锁并发编程  # java并发编程StampedLock高性能读写锁详解  # java并发编程中ReentrantLock可重入读写锁  # Java并发之搞懂读写锁  # Java并发编程之ReadWriteLock读写锁的操作方法  # Java并发编程之显示锁ReentrantLock和ReadWriteLock读写锁  # Java多线程之ReentrantReadWriteLock源码解析  # Java多线程 ReentrantReadWriteLock原理及实例详解  # 一文了解Java读写锁ReentrantReadWriteLock的使用  # 详解Java ReentrantReadWriteLock读写锁的原理与实现  # Java并发读写锁ReentrantReadWriteLock 使用场景  # 正常运行  # 多个  # 都是  # 死锁  # 有一个  # 有什么  # 随机数  # 是指  # 可以看出  # 顾名思义  # 则可  # 则在  # 可以随时  # 能再  # 绑定  # 抛出  # 小编  # 之重  # 有什么区别  # 图中 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel怎么实现观察者模式Observer_Laravel模型事件监听与解耦开发【指南】  公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?  Laravel如何处理CORS跨域请求?(配置示例)  JS实现鼠标移上去显示图片或微信二维码  Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区  javascript基于原型链的继承及call和apply函数用法分析  js实现获取鼠标当前的位置  北京的网站制作公司有哪些,哪个视频网站最好?  Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】  动图在线制作网站有哪些,滑动动图图集怎么做?  Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】  Laravel如何保护应用免受CSRF攻击?(原理和示例)  Laravel如何发送系统通知?(Notification渠道示例)  简单实现jsp分页  如何在新浪SAE免费搭建个人博客?  Laravel怎么连接多个数据库_Laravel多数据库连接配置  Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程  网站建设保证美观性,需要考虑的几点问题!  Laravel Blade模板引擎语法_Laravel Blade布局继承用法  Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载  Laravel如何使用Gate和Policy进行授权?(权限控制)  Laravel表单请求验证类怎么用_Laravel Form Request分离验证逻辑教程  网站建设要注意的标准 促进网站用户好感度!  成都品牌网站制作公司,成都营业执照年报网上怎么办理?  Laravel Seeder填充数据教程_Laravel模型工厂Factory使用  Laravel Session怎么存储_Laravel Session驱动配置详解  网站制作壁纸教程视频,电脑壁纸网站?  香港服务器网站卡顿?如何解决网络延迟与负载问题?  头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?  Laravel如何使用.env文件管理环境变量?(最佳实践)  JavaScript中的标签模板是什么_它如何扩展字符串功能  Laravel如何处理和验证JSON类型的数据库字段  高防服务器:AI智能防御DDoS攻击与数据安全保障  如何在云虚拟主机上快速搭建个人网站?  网站建设整体流程解析,建站其实很容易!  Android Socket接口实现即时通讯实例代码  Laravel如何实现多对多模型关联?(Eloquent教程)  Laravel如何使用Blade组件和插槽?(Component代码示例)  Python面向对象测试方法_mock解析【教程】  如何快速搭建支持数据库操作的智能建站平台?  canvas 画布在主流浏览器中的尺寸限制详细介绍  ChatGPT回答中断怎么办 引导AI继续输出完整内容的方法  昵图网官方站入口 昵图网素材图库官网入口  东莞专业网站制作公司有哪些,东莞招聘网站哪个好?  如何用PHP快速搭建CMS系统?  简单实现Android文件上传  Android实现代码画虚线边框背景效果  制作电商网页,电商供应链怎么做?  EditPlus 正则表达式 实战(3)  html5源代码发行怎么设置权限_访问权限控制方法与实践【指南】