深入学习锁--Lock各种使用方法

一、什么是Lock

Lock是一个接口,通常所说的可重入锁是指Lock的一个实现子类ReentrantLock

二、Lock实现步骤: 

①创建锁对象Lock lock = new ReentrantLock();

②加锁lock.lock();

③释放锁lock.unlock();

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * 手动锁(可重入锁的基本使用)
 */
public class ThreadLock {
    public static void main(String[] args) {
        //1.创建锁对象
        Lock lock = new ReentrantLock();
        //2.加锁操作
        lock.lock();
        try{
            //业务代码(可能会非常复杂->可能会导致异常,后面的代码就不执行了,锁就无法释放,当前线程会永久占用锁资源)
            //所以要用try-catch-finally(可以没有catch)
            System.out.println("你好,ReentrantLock.");
        } finally {
            //3.释放锁(一定要放在finally中)
            lock.unlock(); 
        }
    }
}

--->注意事项:

1.unlock()一定要放在finally里,否则可能导致锁资源永久占用问题。

2.lock()要放到try外(官方建议)或try中的首行(问题不大)。

lock.lock();  
try {
    
} finally {
    lock.unlock()
}
try {
    lock.lock(); 
    int n = 1/0; 
} finally {
    lock.unlock()
}

--->这种不行

try {
    int n = 1/0;
    lock.lock();  
} finally {
    lock.unlock()
}

原因有两个:

  1. 如果放在 try ⾥⾯,因为 try 代码中的异常导致加锁失败,但还会执行 finally 释放锁的操作。 未加锁却释放锁,肯定会报错。
  2. 报错信息中:unlock 异常会覆盖 try ⾥⾯的业务异常,从而增加调式程序和修复程序的复杂度,增加排查错误的难度。

三、Lock指定锁类型——公平锁和非公平锁

//1.创建锁对象
Lock lock = new ReentrantLock(true); //公平锁
Lock lock = new ReentrantLock(); //非公平锁
Lock lock = new ReentrantLock(false); //非公平锁 

使用公平锁比使用非公平锁要慢!

四、(面试必问)

4.1synchronized VS Lock(ReentrantLock)

  1. 实现方式:Synchronized是Java语言内置的关键字,而Lock是一个Java接口。
  2. 锁的获取和释放:Synchronized是隐式获取和释放锁,由Java虚拟机自动完成;而Lock需要显式地调用lock()方法获取锁,并且必须在finally块中调用unlock()方法来释放锁。
  3. 可中断性:在获取锁的过程中,如果线程被中断,synchronized会抛出InterruptedException异常并且自动释放锁,而Lock则需要手动捕获InterruptedException异常并处理,同时也支持非阻塞、可轮询以及定时获取锁的方式。
  4. 公平性:Synchronized不保证线程获取锁的公平性,而Lock可以通过构造函数指定公平或非公平锁。
  5. 锁状态:Synchronized无法判断锁的状态,而Lock可以通过tryLock()、isLocked()来判断锁的状态(线程是否可能取到锁、锁是否被占用等)。
  6. 粒度:Synchronized锁的粒度较粗,只能锁住整个方法或代码块,而Lock可以细粒度地控制锁的范围,比如锁某个对象的部分属性。
  7. 场景:如果在简单的并发场景下,推荐使用Synchronized;而在需要更高级的锁控制时,可以考虑使用Lock。

一般情况建议使用Synchronized,在JDK1.5之前Lock优于Synchronized,但在JDK1.5之后对Synchronized进行了优化,后面在性能方面基本与Lock一样且使用简单(有作者说"Synchronized是亲生的,JDK还是会一直优化他不会让Lock优于它")。

4.2 Synchronized原理 

Synchronized是Java语言中最常用的同步机制之一,它可以确保多个线程访问共享资源时的互斥性和可见性。Synchronized关键字的原理如下:

  1. Synchronized使用了内置锁(也称为监视器锁)来实现同步。每个Java对象都有一个内置锁,当该对象作为锁被获取时,其他试图获取该锁的线程会被阻塞,直到该锁被释放。
  2. Synchronized的锁是与对象相关联的。当一个线程进入Synchronized代码块时,它必须先获取该对象的锁才能执行代码,否则就会被阻塞。当该线程退出Synchronized代码块时,它会自动释放该对象的锁。
  3. Synchronized具有可重入性。如果当前线程已经获得了某个对象的锁,那么它可以继续访问该对象的其他Synchronized代码块,而不会被自己持有的锁所阻塞。
  4. Synchronized还具有volatile变量的读写语义。在使用Synchronized关键字时,内存屏障会确保本地线程中修改过的变量值被刷新回主内存,从而保证了多个线程之间对变量修改的可见性。

Synchronized通过使用内置锁、与对象关联的锁、可重入性以及内存屏障等机制来实现线程的同步和锁的管理,以保证对共享资源的访问具有互斥性和可见性。

4.3 Lock原理

Lock是Java语言中的一种高级同步机制,它提供了比Synchronized更加灵活和可扩展的同步特性。Lock机制的原理如下:

  1. Lock使用了对象的锁来实现同步。每个Lock对象都有一个锁,当该锁被获取时,其他试图获取该锁的线程会被阻塞,直到该锁被释放。
  2. Lock的锁是与对象无关的。相比于Synchronized关键字,Lock提供了更加灵活的方式来控制锁的获取和释放。例如,它支持可中断的获取锁操作、超时获取锁操作等等。因此,在需要手动控制锁的获取和释放时,Lock是一个很好的选择。
  3. Lock还具有可重入性。如果当前线程已经获得了某个Lock对象的锁,那么它可以继续访问该对象的其他Lock代码块,而不会被自己持有的锁所阻塞。
  4. Lock使用了条件变量来实现线程的等待和通知。Condition接口提供了await()、signal()和signalAll()等方法,用于线程之间的等待和通知,从而避免了Object类中wait()和notify()方法可能出现的信号丢失问题。

Lock通过使用对象的锁、与对象无关的锁、可重入性以及条件变量等机制来实现线程的同步和锁的管理,以保证对共享资源的访问具有互斥性和可见性。与Synchronized关键字相比,Lock提供了更加灵活和可扩展的同步特性,但也需要更多的代码来控制锁的获取和释放。

4.4、Synchronized与Lock使用

Synchronized

public class Counter {
        private int count;

        public synchronized void increment() {
            count++;
        }
    }

Lock

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    private int count;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}

上述代码也是定义了一个计数器类Counter,但是使用的是Lock接口来实现线程同步。在这种情况下,需要先创建一个ReentrantLock对象,然后在需要同步的代码块中调用lock()方法获取锁,在finally块中调用unlock()方法释放锁。

总的来说,Synchronized更加简单易用,适合用于一些简单的并发场景;而Lock提供了更多的灵活性和可扩展性,适合用于一些复杂的并发场景。

4.5ReentrantLock为什么比Synchronized更灵活?

ReentrantLock比Synchronized更灵活主要因为它提供了以下功能:

  • 可以指定公平锁或非公平锁。
  • 支持获取锁的超时时间。
  • 支持可中断的获取锁操作。
  • 可以通过tryLock()方法尝试获取锁,如果锁已经被占用,则返回false。
  • 支持多个Condition对象,可以让线程在不同的条件下等待和唤醒。

4.6什么是锁自旋?

锁自旋是一种优化锁竞争的技术,它用于减少线程在获取锁时的等待时间。当一个线程请求获取某个对象的锁时,如果此时锁已经被其他线程占用,那么该线程会进入阻塞状态等待锁的释放。而使用锁自旋技术,线程在发现锁被其他线程占用时,并不会立即进入阻塞状态,而是执行一段循环代码(称为自旋),等待锁的持有者释放锁。

原文链接:https://zhuanlan.zhihu.com/p/622760822

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智安网络|语音识别技术:从历史到现状与未来展望

语音识别技术是一种将语音信号转化为可识别的文本或命令的技术,近年来得到了广泛应用和关注。 一. 语音识别的发展现状 1.历史发展 语音识别技术的起源可以追溯到20世纪50年代,但直到近年来取得了显著的突破和进展。随着计算机性能的提升和深度学习算法…

nn.AdaptiveAvgPool2d(output_size)输入和输出怎么回事?

前言 nn.AdaptiveAvgPool2d(output_size) 函数作用:自适应进行平均池化。不用管输入、stride、padding,函数参数只有输出大小,其他的这个函数帮你搞定。 问题就是,我想知道他是咋搞定的? 1 函数的使用 先把例子摆上…

认识Docker

Docker 是世界领先的软件容器平台,所以想要搞懂 Docker 的概念我们必须先从容器开始说起。 1.1 什么是容器? 先来看看容器较为官方 一句话概括容器:容器就是将软件打包成标准化单元,以用于开发、交付和部署。 容器镜像是轻量的、可执行的…

openEuler 20.03 (LTS-SP2) aarch64 cephadm 部署ceph18.2.0【1】离线部署 准备基础环境

准备3台虚拟机服务器(均可访问公网) 10.2.1.176 (作为操作机) 10.2.1.191 10.2.1.219 安装基础工具 yum install -y vim 配置hosts 编辑/etc/hosts,添加 10.2.1.176 ceph-176 10.2.1.191 ceph-191 10.2.1.219 ceph-219 配置免密登录…

Nginx 简单入门操作

前言:之前的文章有些过就不罗嗦了。 Nginx 基础内容 是什么? Nginx 是一个轻量级的 HTTP 服务器,采用事件驱动、异步非阻塞处理方式的服务器,它具有极好的 IO 性能,常用于 HTTP服务器(包含动静分离)、正向代理、反向代理、负载均衡 等等. Nginx 和 Node.js 在很多方…

harmonyOS学习笔记之stateStyles

stateStyles:多态样式 stateStyles可以依据组件的内部状态的不同,设置不同的样式 stateStyles是属性方法,可以根据状态来设置样式,类似于css伪类,但是语法不一样,ArkUI提供了四种状态: focused:获焦态 normal:正常态 pressed:按压态 disable:不可用态例如: Entry Component …

【云原生系列】Kubernetes知识点

目录 概念 基础架构 单master节点 多master节点 组件 Master节点核心组件 其他组件 请求发送流程 插件 核心资源 调度资源 Pod 创建pod组件间调用流程 pod生命周期: 初始化容器 镜像拉取策略 重启策略 钩子函数 探针 探针的实现方式 DownwardAP…

文档保密不漏泄:上海迅软DSE提升企业效率的文档管理利器大揭秘!

你是否面临这些问题?公司的电子文档繁多且分散,无法统一管理;员工粗心误删重要文件,导致文件无法找回;硬盘驱动损坏,数据丢失无法恢复;办公电脑丢失,数据不但找不回来,重…

idea连接mysql详细讲解

IDEA连接mysql又报错!Server returns invalid timezone. Go to Advanced tab and set serverTimezone prope 前进的道路充满荆棘。 错误界面 IDEA连接mysql,地址,用户名,密码,数据库名,全都配置好了&…

gitlab高级功能之mirroring - push mirroring(一)

今天给大家介绍一个gitlab很高级也是非常有用的功能 - gitlab的mirroring,你可以将仓库镜像到外部或从外部镜像仓库过来,从而可以实现分支、标签和提交的自动同步。 文章目录 1. mirroring的实现方式2. push mirroring2.1 简介2.2 说明 3. 配置推送镜像3…

15、pytest的fixture调用fixture

官方实例 # content of test_append.py import pytest# Arrange pytest.fixture def first_entry():return "a"# Arrange pytest.fixture def order(first_entry):return [first_entry]def test_string(order):# Actorder.append("b")# Assertassert orde…

车间工人个人简历15篇

在车间工人职位的求职过程中想脱颖而出,获得心仪的工作机会,参考这15篇精选的车间工人简历案例,无论您是初学者还是经验丰富的工人,这些专业简历将为您提供灵感和实用建议。让您的简历吸引HR的关注,轻松斩获心仪职位。…

基于ssm 传统文化资源库导览系统-计算机毕设 附源码 63347

ssm 传统文化资源库导览系统 目 录 摘 要 Abstract 第1章 前 言 1.1 研究背景 1.3 系统开发目标 第2章 系统开发环境 2.1 java技术 2.4 SSM框架 第3章 需求分析 3.1 需求分析 3.2 系统可行性分析 3.3 项目设计目标与原则 3.4 系统流程分析 第4章 架…

软件测试:测试用例八大要素模板

一、通用测试用例八要素 1、用例编号; 2、测试项目; 3、测试标题; 4、重要级别; 5、预置条件; 6、测试输入; 7、操作步骤; 8、预期输出 二、具体分析通用测试用例八要素 1、用例编号 一般是数字…

知虾主页:为商家和市场分析师提供的数据分析工具

知虾是专为Shopee(虾皮购物)平台而设计的数据分析工具,为商家和市场分析师提供了丰富的功能和信息。本文将介绍知虾主页上的各项功能,并详细解释如何利用这些功能来分析市场趋势、产品分析和竞争对手分析等方面的数据。无论您是新…

LeetCode:1038. 从二叉搜索树到更大和树(反向中序遍历 C++、Java)

目录 1038. 从二叉搜索树到更大和树 题目描述: 实现代码与解析: dfs 原理思路: 1038. 从二叉搜索树到更大和树 题目描述: 给定一个二叉搜索树 root (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所…

机器学习之——诈骗号码识别

研究目的 根据用户的app使用情况,用户的流量使用情况,用户通话记录,用户的短信记录,判定用户号码是否是诈骗号码。数据集 train: train_app.csv:app使用情况 . train_user.csv:基本信息 . train…

【数据结构】手撕排序NO.1

🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 文章目录 一、排序的概念及其运用1.1 排序的概念1.2 常见的算法排序 二、 冒泡排序三、直接插入排…

【注册表】Sublime Text添加到右键菜单

官网下载 windows下地地址: http://www.sublimetext.com/download_thanks?targetwin-x64设置右键菜单和菜单小图标 win R打开运行,并输入regedit打开注册表编辑器依次找到HKEY_CLASSESS_ROOT -> * -> Shell,下面新建项, 这个项的名…

HTML5+CSS3+Vue小实例:浪漫的心形文字动画特效

实例:浪漫的心形文字动画特效 技术栈:HTML+CSS+Vue 效果: 源码: 【HTML】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" conte…