Java内置锁:深度解析lock和trylock

news2024/9/27 7:14:55

Java内置锁:深度解析lock和trylock - 程序员古德

locktryLock是两种获取锁的方式,它们在处理并发问题时有所不同,lock是阻塞性的,确保只有一个线程能访问被锁资源,但可能导致线程长时间等待;而tryLock非阻塞性,若锁被占用则立即返回失败,避免了长时间等待,但需要更复杂的逻辑处理未能获锁的情况。

定义

Java内置锁:深度解析lock和trylock - 程序员古德

在Java 11中,Lock接口是Java并发编程中一个重要的接口,它提供了更灵活的线程同步机制,相比于内置的synchronized关键字,Lock接口中主要有两个方法用于获取锁:lock()tryLock()

参考文档:https://docx.iamqiang.com/jdk11/api/java.base/java/util/concurrent/locks/Lock.html

lock()方法是一个阻塞式的方法,当线程调用这个方法时,如果锁已经被其他线程持有,那么当前线程就会进入等待状态,直到获得锁为止,在这个过程中,线程会一直等待,不会做其他的事情,这就好比在一个繁忙的餐厅外等待空位,如果没有空位,就只能站着等,不能做其他事情,直到有空位为止。

tryLock()方法则是一个非阻塞式的方法,当线程调用这个方法时,如果锁已经被其他线程持有,那么这个方法会立即返回,不会让线程进入等待状态,如果锁没有被其他线程持有,那么当前线程就会立即获得锁,这就像在餐厅外等待空位,但是不确定是否有空位,所以先问一下服务员,如果有空位就坐下,如果没有就去其他地方看看或者做其他事情。

代码案例

Java内置锁:深度解析lock和trylock - 程序员古德

lock方法使用

参考文档:https://docx.iamqiang.com/jdk11/api/java.base/java/util/concurrent/locks/Lock.html#lock()

下面举一个例子,模拟一个餐厅,其中有固定数量的座位,客户(线程)需要获取锁(座位)才能在餐厅就餐,如果座位被占用,客户将等待直到有座位可用。

创建一个餐厅类餐厅类Restaurant,导入java.util.concurrent.locks.Lockjava.util.concurrent.locks.ReentrantLock,如下代码:

import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReentrantLock;  
  
public class Restaurant {  
    // 餐厅的座位,用Lock表示  
    private final Lock seat = new ReentrantLock();  
  
    // 客户进入餐厅并坐下  
    public void enterAndSit() {  
        // 客户尝试获取座位锁  
        seat.lock();  
        try {  
            // 客户已经坐下,这里可以执行就餐的相关操作  
            System.out.println(Thread.currentThread().getName() + " 已进入餐厅并坐下。");  
            // 模拟就餐时间  
            try {  
                Thread.sleep(1000); // 等待1秒  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        } finally {  
            // 客户离开时释放座位锁  
            seat.unlock();  
            System.out.println(Thread.currentThread().getName() + " 已离开餐厅。");  
        }  
    }  
}

创建一个client类来模拟多个客户同时尝试进入餐厅,如下代码:

public class RestaurantClient {  
  
    public static void main(String[] args) {  
        // 创建一个餐厅实例  
        Restaurant restaurant = new Restaurant();  
  
        // 模拟多个客户线程  
        for (int i = 0; i < 5; i++) {  
            new Thread(() -> {  
                restaurant.enterAndSit();  
            }, "客户" + Thread.currentThread().getId()).start();  
        }  
    }  
}

运行RestaurantClient会看到类似以下的输出(由于线程调度的不确定性,输出顺序可能会有所不同):

客户13 已进入餐厅并坐下。  
客户13 已离开餐厅。  
客户12 已进入餐厅并坐下。  
客户12 已离开餐厅。  
客户11 已进入餐厅并坐下。  
客户11 已离开餐厅。  
客户10 已进入餐厅并坐下。  
客户10 已离开餐厅。  
客户9 已进入餐厅并坐下。  
客户9 已离开餐厅。

从输出中可以看到,尽管同时启动了5个客户线程,但它们是顺序地进入餐厅并坐下的,这是因为lock()方法是阻塞的,当一个客户获得座位锁时,其他客户必须等待直到锁被释放,这就确保了餐厅在任何时候都不会有超过其座位数的客户同时就餐。

trylock方法使用

参考文档:https://docx.iamqiang.com/jdk11/api/java.base/java/util/concurrent/locks/Lock.html#tryLock()

接着模拟餐厅排队的场景,这次使用Lock接口中的tryLock()方法,如果座位不可用,则他们可以选择做其他事情,而不是无限期等待,先定义餐厅类Restaurant,使用ReentrantLock作为座位锁,如下代码:

import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReentrantLock;  
  
public class Restaurant {  
    // 餐厅的座位,用Lock表示  
    private final Lock seat = new ReentrantLock();  
  
    // 客户尝试进入餐厅并坐下,如果无法立即获得座位则返回false  
    public boolean tryEnterAndSit() {  
        // 客户尝试获取座位锁,如果成功则进入餐厅,否则返回false  
        boolean acquired = seat.tryLock();  
        if (acquired) {  
            try {  
                // 客户已经坐下,这里可以执行就餐的相关操作  
                System.out.println(Thread.currentThread().getName() + " 已进入餐厅并坐下。");  
                // 模拟就餐时间  
                try {  
                    Thread.sleep(1000); // 等待1秒  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            } finally {  
                // 客户离开时释放座位锁  
                seat.unlock();  
                System.out.println(Thread.currentThread().getName() + " 已离开餐厅。");  
            }  
        } else {  
            // 客户未能获得座位  
            System.out.println(Thread.currentThread().getName() + " 无法进入餐厅,座位已被占用。");  
        }  
        return acquired;  
    }  
}

创建一个client类来模拟多个客户同时尝试进入餐厅,如下代码:

public class RestaurantClient {  
  
    public static void main(String[] args) {  
        // 创建一个餐厅实例  
        Restaurant restaurant = new Restaurant();  
  
        // 模拟多个客户线程  
        for (int i = 0; i < 5; i++) {  
            new Thread(() -> {  
                // 尝试进入餐厅  
                boolean success = restaurant.tryEnterAndSit();  
                // 如果未能进入餐厅,则做其他事情  
                if (!success) {  
                    System.out.println(Thread.currentThread().getName() + " 选择去其他地方。");  
                }  
            }, "客户" + (i + 1)).start();  
        }  
    }  
}

运行RestaurantClient会看到类似以下的输出(由于线程调度的不确定性,输出顺序可能会有所不同):

客户1 已进入餐厅并坐下。  
客户2 无法进入餐厅,座位已被占用。  
客户2 选择去其他地方。  
客户3 无法进入餐厅,座位已被占用。  
客户3 选择去其他地方。  
客户4 无法进入餐厅,座位已被占用。  
客户4 选择去其他地方。  
客户5 无法进入餐厅,座位已被占用。  
客户5 选择去其他地方。  
客户1 已离开餐厅。

从输出中可以看到,只有第一个客户成功进入了餐厅,因为tryLock()方法是非阻塞的,当一个客户获得座位锁时,其他客户会立即得到反馈,知道座位不可用,并选择了做其他事情,这就展示了tryLock()方法如何在避免线程长时间等待发挥作用。

核心总结

Java内置锁:深度解析lock和trylock - 程序员古德

lock方法是一种阻塞性的获取锁的方式,当调用一个对象的lock方法时,如果锁当前被其他线程持有,那么当前线程将会被挂起(即阻塞),直到锁被释放,这种机制确保了只有一个线程能够在同一时间访问被锁保护的代码块或资源,从而避免了并发问题,但是,它也可能导致线程长时间等待,特别是在高并发环境下,如果锁的持有者因为某些原因(如死锁)未能及时释放锁,那么其他线程可能会一直等待下去。

tryLock方法则是一种非阻塞性的获取锁的方式,当调用一个对象的tryLock方法时,如果锁当前可用,那么将成功获得锁并继续执行;如果锁被其他线程持有,那么不会被挂起,而是立即得到一个失败的结果(通常是一个布尔值false),这种方式的好处是可以避免线程长时间等待,因为可以立即知道是否获得了锁,但是,这也意味着可能需要编写更复杂的逻辑来处理未能获得锁的情况,例如通过重试机制或执行备选方案等。

总结:如果希望确保线程能够按照特定的顺序访问共享资源,并且不介意可能的等待时间,那么lock方法是一个不错的选择,但是,如果希望避免线程长时间等待,并且能够处理未能立即获得锁的情况,那么tryLock方法可能更适合。

关注我,每天学习互联网编程技术 - 程序员古德

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1379925.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据人工智能在线实习项目:某实习网站招聘信息采集与分析

01前置课程 Python编程基础 Python网络爬虫实战 Python爬虫环境与爬虫简介 网页前端基础 简单静态网页爬取 常规动态网页爬取 模拟登录 Python数据分析与应用、可视化 数据分析概述 Numpy数值计算 Pandas统计分析与数据预处理 Matplotlib可视化 Pyecharts绘图 02师…

【华为鸿蒙】HarmonyOS开发学习:下载与安装软件看这一篇就够了!

下载与安装软件 DevEco Studio 支持 Windows 和 macOS 系统&#xff0c;下面将针对两种操作系统的软件安装方式进行介绍 Windows 环境 运行环境要求 为保证 DevEco Studio 正常运行&#xff0c;建议您的电脑配置满足如下要求&#xff1a;  操作系统&#xff1a;Windows10 …

【光波电子学】基于MATLAB的多模光纤模场分布的仿真分析

基于MATLAB的多模光纤模场分布的仿真分析 一、引言 &#xff08;1&#xff09;多模光纤的概念 多模光纤&#xff08;MMF&#xff09;是一种具有较大纤芯直径的光纤结构&#xff0c;其核心直径通常在10-50微米范围内。与单模光纤&#xff08;SMF&#xff09;相比&#xff0c;…

回归预测 | MATLAB实现SSA-CNN-GRU-Attention多变量回归预测(SE注意力机制)

回归预测 | MATLAB实现SSA-CNN-GRU-Attention多变量回归预测&#xff08;SE注意力机制&#xff09; 目录 回归预测 | MATLAB实现SSA-CNN-GRU-Attention多变量回归预测&#xff08;SE注意力机制&#xff09;预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab实现SSA…

XCTF:就在其中[WriteUP]

使用Wrireshark打开文件 点击‘统计’&#xff0c;查看协议分级 按占比分析 该数据包应该是在使用ftp协议传输文件 将其选中作为过滤器 以此将其分类&#xff0c;方便分析传输了什么文件 回到主界面 再点击‘分析‘选择追踪流 选择TCP Stream 绿框内是传输的所有文件&…

【排序篇2】选择排序、计数排序

目录 一、选择排序二、计数排序 一、选择排序 整体思想&#xff1a; 从数组中选出最小值和最大值放在起始位置&#xff0c;直到排序完成 具体步骤&#xff1a; 定义两个变量begin和end为下标&#xff0c;指向数组始末定义要找的最大值的下标为maxi&#xff0c;最小值的下标为…

Unity中URP下实现深度贴花(雾效支持和BRP适配)

文章目录 前言一、让我们的贴画支持雾效1、我们舍弃内部的MixFog方法2、使用 雾效混合因子 对最后输出颜色进行线性插值相乘 二、在Shader中&#xff0c;限制贴花纹理的采样方式1、申明 纹理 和 限制采样方式的采样器2、在片元着色器进行纹理采样 三、BRP适配1、C#脚本中&#…

0104 AJAX介绍

Ajax 的全称是 Asynchronous Javascript And XML &#xff08;异步 JavaScript 和 XML &#xff09;。 通俗的理解&#xff1a;在网页中利用 XMLHttpRequest 对象和服务器进行数据交互的方式&#xff0c;就是 Ajax Ajax 能让我们轻松实现网页与服务器之间的数据交互。 浏览器…

大语言模型下载,huggingface和modelscope加速

huggingface 下载模型 如果服务器翻墙了&#xff0c;不用租机器 如果服务器没翻墙&#xff0c;可以建议使用下面的方式 可以租一台**autodl**不用显卡的机器&#xff0c;一小时只有1毛钱&#xff0c;启动学术加速&#xff0c;然后下载&#xff0c;下载完之后&#xff0c;用scp…

AI的力量:微软超越苹果,成为全球最有价值公司

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Sectigo的DV通配符https

Sectigo是近些年发展比较快速的CA认证机构&#xff0c;为了提升审核效率&#xff0c;在全国成立了审核机构&#xff0c;亚太审核中心的成立加快了Sectigo旗下的https证书的审核速度。Sectigo的https证书可以为网站安全提供有力支持&#xff0c;从而保护网站信息安全。今天就随S…

每日一题 2182. 构造限制重复的字符串(中等,贪心)

贪心&#xff0c;每次都尽量取大的&#xff0c;除非连续取的次数超出限制&#xff0c;此时取一个下一个字符 class Solution:def repeatLimitedString(self, s: str, repeatLimit: int) -> str:N 26count [0] * Nfor c in s:count[ord(c) - ord(a)] 1ret []i, j, m N …

极智一周 | AI大模型应用、AI发展系列、Animate Anyone、自动驾驶芯片、DRIVE And so on

欢迎关注我的公众号 [极智视界]&#xff0c;获取我的更多技术分享 大家好&#xff0c;我是极智视界&#xff0c;带来本周的 [极智一周]&#xff0c;关键词&#xff1a;AI大模型应用、AI发展系列、Animate Anyone、自动驾驶芯片、DRIVE And so on。 邀您加入我的知识星球「极智…

电脑连不上网?解决方法看这里

随着互联网的普及&#xff0c;电脑成为我们日常工作不可或缺的一部分。然而&#xff0c;有时我们可能会面临电脑连不上网的问题&#xff0c;这给我们的工作和娱乐带来了一些困扰。本文将介绍解决电脑无法连接网络的三种有效方法&#xff0c;帮助读者迅速恢复网络连接&#xff0…

FreeRtos Queue (一)

本篇主要讲队列的数据结构和初始化 一、队列的数据结构 二、队列初始化完是什么样子的 队列初始化的函数调用关系&#xff1a;xQueueGenericCreate->prvInitialiseNewQueue->xQueueGenericReset 所以&#xff0c;最终初始化完的队列是这样的 假设申请了4个消息体&…

Windows Redis图形客户端 Another Redis Desktop Manager的简单使用教程

1、 Redis官方文档 2、 Redis国内中文版文档 3、 Redis客户端 Another Redis Desktop Manager 4、连接redis服务 我直接使用的是公司搭建好的服务。连接服务需要以下几个信息&#xff1a; HostPortPasswordSSL 5、New Key 5.1 如何创建一个Key&#xff1f; 点击New k…

Java多线程并发篇----第十一篇

系列文章目录 文章目录 系列文章目录前言一、什么是悲观锁二、什么是自旋锁三、Synchronized 同步锁前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一、什么是悲观…

NVMe over TCP高性能文件存储,让未来照进现实,400us

你真的懂NVMe吗&#xff1f; 在说NVMe之前&#xff0c;我们觉得有必要先聊一聊NVM&#xff08;Non-Volatile Memory&#xff09;&#xff0c;即非易失性内存。从名字上看就知道&#xff0c;NVM是一种类内存式&#xff08;访问及寻址方式类似&#xff09;的设备&#xff0c;它必…

小鼠的滚动疲劳仪-转棒实验|ZL-200C小鼠转棒疲劳仪

转棒实验|ZL-200C小鼠转棒疲劳仪用于检测啮齿类动物的运动功能。通过测量动物在滚筒上行走的持续时间&#xff0c;来评定**神经系统*病或损坏以及药物对运动协调功能和疲劳的影响。 疲劳实验中&#xff0c;让小鼠在不停转动的棒上运动&#xff0c;肌肉会很快进入疲劳状态&#…

办理美国FCC认证的意义是什么?

首先是法律法规的要求&#xff1b; 其次&#xff0c;客户认可&#xff0c;声誉&#xff1b; 最后&#xff0c;办理美国FCC认证的意义主要体现在以下几个方面&#xff1a; 保障公共利益&#xff1a;FCC认证要求产品符合美国联邦通信委员会制定的规定&#xff0c;防止不符合标准…