java--Lock锁

news2024/11/15 9:06:24

1.概述

锁是一种工具,用于控制对共享资源的访问

Lock和synchronized,这两个是最常见的锁,它们都可以达到线程安全的目的,但是在使用上和功能上又有较大的不同。

Lock并不是用来代替synchronized的,而是当使用synchronized不合适或不足以满足要求的时候,来提供高级功能的。

Lock接口最常见的实现类,是ReentrantLook

通常情况下,Lock只允许一个线程来访问这个共享资源,不过有时候,一些特殊的实现也可允许并发访问。比如,ReadWriteLock里面的ReadLock。

  • 为什么synchronized不够用

1.效率低:所得释放情况少,试图获得锁的时候不能设定超时,不能中断一个正在试图获得锁的线程

2.不够灵活:枷锁和释放锁时机单一,每个所仅有单一的条件某个对象,可能是不够的。

2Lock锁的主要方法介绍

  • 在lock声明了四个方法来获取锁
  • lock(),tryLock(),tryLock(long time,TimeUnit unit)和LockInterruptibly()

3lock()

lock()就是最普通的获取锁。如果锁已被其他线程获取,则进行等待

Lock()不会像synchronized一样在异常时自动释放锁

因此最佳实践是,在finally中释放锁,以保证发生异常时锁一定被释放

package cn.butool.lock;

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

/**
 * Lock()不会像synchronized一样在异常时自动释放锁
 * 因此最佳实践是,在finally中释放锁,以保证发生异常时锁一定被释放
 */
public class MustUnLock {
    private static Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        // 加锁
        lock.lock();
        try{
            //获取本锁,保护的资源
            System.out.println(Thread.currentThread().getName()+"开始执行任务");
        }finally {
            // 释放锁
            lock.unlock();
        }
    }
}

 4tryLock()、tryLock(long time,TimeUnit unit)

  1. lock()方法不能被中断,一旦陷入死锁,这会带来很大的隐患lock()就会陷入永久等待 ;
  2. tryLock()用来尝试获取锁,如果当前锁没有被其他线程占用,则获取成功,则返回true,否则返回false,代表获取锁失败。
  3. 该方法会立即返回,即便在拿不到锁时不会一直在那等
  4. tryLock(long time,TimeUnit unit)超时就放弃

5用tryLock来避免死锁

5.1代码

package cn.butool.lock;

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

/**
 * 用TryLock来避免死锁
 */
public class TryLockDeadLock implements Runnable{

    public static void main(String[] args) {
        TryLockDeadLock r1 = new TryLockDeadLock();
        TryLockDeadLock r2 = new TryLockDeadLock();
        r1.flag=1;
        r2.flag=0;
        new Thread(r1).start();
        new Thread(r2).start();
    }
    int flag =1;
    static Lock locl1 = new ReentrantLock();
    static Lock locl2 = new ReentrantLock();
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(flag ==1){
                try {
                    if(locl1.tryLock(800, TimeUnit.MILLISECONDS)){
                        try {
                            System.out.println("线程1获取到了锁1");
                            Thread.sleep(new Random().nextInt(1000));

                            if(locl2.tryLock(800, TimeUnit.MILLISECONDS)){
                                try{
                                    System.out.println("线程1获取到了锁2");
                                    System.out.println("线程1获取到了2把锁");
                                    break;
                                }finally {
                                    locl2.unlock();
                                }
                            }else{
                                System.out.println("线程1获取锁2失败,已重试");
                            }

                        }finally {
                            locl1.unlock();
                            Thread.sleep(new Random().nextInt(1000));
                        }
                    }else{
                        System.out.println("线程1获取锁1失败,已重试");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if(flag ==0){
                try {
                    if(locl2.tryLock(3000, TimeUnit.MILLISECONDS)){
                        try {
                            System.out.println("线程2获取到了锁2");
                            Thread.sleep(new Random().nextInt(1000));

                            if(locl1.tryLock(800, TimeUnit.MILLISECONDS)){
                                try{
                                    System.out.println("线程2获取到了锁1");
                                    System.out.println("线程2获取到了2把锁");
                                    break;
                                }finally {
                                    locl1.unlock();
                                }
                            }else{
                                System.out.println("线程2获取锁1失败,已重试");
                            }

                        }finally {
                            locl2.unlock();
                            Thread.sleep(new Random().nextInt(1000));
                        }
                    }else{
                        System.out.println("线程2获取锁1失败,已重试");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

5.2打印

线程1获取到了锁1
线程2获取到了锁2
线程2获取锁1失败,已重试
线程1获取到了锁2
线程1获取到了2把锁
线程2获取到了锁2
线程2获取到了锁1
线程2获取到了2把锁

 6LockInterruptibly()

 相当于tryLock(long time, TimeUnit unit)把超时时间设置为无限。在等待锁的过程中,线程可以被中断

6.1代码

package cn.butool.lock;

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

public class LockInterruptiblyTest implements Runnable{
    public static void main(String[] args) {
        LockInterruptiblyTest lockInterruptiblyTest = new LockInterruptiblyTest();
        Thread thread1 = new Thread(lockInterruptiblyTest);
        Thread thread2 = new Thread(lockInterruptiblyTest);
        thread1.start();
        thread2.start();
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread1.interrupt();
    }
    private Lock lock = new ReentrantLock();
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"尝试获取锁");
        try {
            lock.lockInterruptibly();
            try {
                System.out.println(Thread.currentThread().getName()+"拿到了锁");

                Thread.sleep(5000);
            }catch (Exception e){
                System.out.println(Thread.currentThread().getName()+"睡眠期间被中断了");
            }
            finally {
                lock.unlock();
                System.out.println(Thread.currentThread().getName()+"释放了锁");
            }
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName()+"等锁期间被中断了");

        }
    }
}

 6.2打印

第一种情况Thread-1拿到了锁:
Thread-0尝试获取锁
Thread-1尝试获取锁
Thread-1拿到了锁
Thread-0等锁期间被中断了
Thread-1释放了锁

第二种情况Thread-0拿到了锁:
Thread-0尝试获取锁
Thread-1尝试获取锁
Thread-0拿到了锁
Thread-0睡眠期间被中断了
Thread-0释放了锁
Thread-1拿到了锁
Thread-1释放了锁

7unLock()解锁

最应该被写到finally里面,并且是第一时间写到finally里面,否则有可能会漏掉,如果漏掉有可能会使程序陷入死锁。

finally {
    lock.unlock();
    System.out.println(Thread.currentThread().getName()+"释放了锁");
}

8可见性保证

在进入synchronized锁时,会去主存中读取此时的最新数据,退出锁时将当前更新刷新到主存中

lack的加解锁和synchronized有同样的内存语义,也就是说下一个线程加锁后可以看到所有前一个线程解锁前发生的所有操作

 

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

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

相关文章

verilog手撕代码3——序列检测和序列发生器

文章目录 前言一、序列检测器1.1 重复序列检测1.1.1 序列缓存对比/移位寄存器法1.1.2 状态机法 1.2 非重复序列检测 二、序列发生器2.1 移位寄存器法2.2 反馈法2.3 计数器法 前言 2023.4.25 2023.4.26 学习打卡&#xff0c;天气转晴 一、序列检测器 1.1 重复序列检测 1.1.1 …

SpringBoot整合EasyExcel上传下载前后端

SpringBoot整合EasyExcel上传下载前后端 需求&#xff0c;在项目启动时加载表格里的数据初始化&#xff0c;前端可以上传全部部门的表格数据&#xff0c;后台根据部门名字解析归类数据和根据表格的部门下载部门数据1.后端1.1创建一个SpringBoot项目&#xff0c;引入依赖1.2 在r…

推荐几个可以免费体验GPT-4的网站

想要体验GPT-4除了每月花20美刀还有别的办法吗&#xff1f;&#xff08;甚至现在有钱都花不了&#xff09; 问就是有的&#xff0c;我搜罗了一些可以免费使用GPT-4的网站&#xff08;注意需要魔法&#xff09;&#xff0c;体验之后觉得还行&#xff0c;推荐给大家。 有别的大…

JavaWeb学习笔记

文章目录 一. HTML二. CSS三. JavaScript1. 引入2.语法/输出语句3. 变量/数据类型4. 运算符5. 流程控制语句6. 函数7. 对象8. 事件监听 四. Servlet1.执行流程2. 生命周期3. 常用方法4. 体系结构5. 配置Servlet 五. JSP1. 简介2. JSP原理3.脚本4.JSP缺点5. EL表达式6. JSTL标签…

AI+HPC?人工智能高性能计算方向就业新路子

刚刚过去的3月&#xff0c;GPT-4刷屏了。吃瓜群众一边津津乐道&#xff0c;一边瑟瑟发抖。随后国产大模型紧随其后&#xff0c;百度的“文心一言”、阿里的“通义千问”、复旦大学的“MOSS”、商汤的“商量”竞赛般的亮家伙&#xff0c;有点全民练模型&#xff0c;人人GPT的味道…

【最新】Jetson Agx Xavier烧录环境到TensorRT加速(高集成,快速简单有效)

一.下载烧录好的基础镜像 1. 基础环境 当前镜像包是ubuntu18.08,镜像。镜像包已安装jetpack 4.6,python3.6 &#xff0c;torch1.7, opencv, tensorrt等&#xff0c;运行模型的基本环境都已搭建。jetpack 是4.6 对应L4T是32.6.1。如下图&#xff1a; (1).下载当前文件包&…

OSCP-Escape(gif绕过)

目录 扫描 WEB 扫描 sudo nmap 192.168.233.113 -p- -sS -sVPORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) 8080/tcp open http Apache…

Golang中的一些关键字(defer、:=、go func())

作者&#xff1a;非妃是公主 专栏&#xff1a;《Golang》 博客主页&#xff1a;https://blog.csdn.net/myf_666 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录 defervar与 : 的区别var:二者区别 go func de…

antDesignPro6项目:供应链系统—实战问题解决汇总

系统使用的技术&#xff1a;antDesignPro6 Umi4 antDesign antDesignProComponents 其他技术 1、如何设置ModalForm组件&#xff0c;销毁时&#xff0c;自动重置表单&#xff1f; modalProps{{ destroyOnClose: true }} // 重置表单 答&#xff1a;给ModalForm组件添加mo…

智加科技+舍弗勒,首发量产正向开发的智能重卡冗余转向

对于自动驾驶赛道来说&#xff0c;感知、规划和控制&#xff0c;除了计算平台、算法等核心上层软硬件支持&#xff0c;底盘控制系统同样是关键一环。事实上&#xff0c;从Demo到规模化量产&#xff0c;更好的车身控制能力以及冗余备份&#xff0c;也是自动驾驶公司迈入2.0阶段的…

中介作用分析流程

中介作用分析流程 一、案例背景 家庭氛围对于学生成长具有重要的意义。好的家庭氛围能够增强学生的家庭幸福感&#xff0c;促进学生良好性格的形成。在这个过程中&#xff0c;父子沟通与母子沟通对于家庭氛围和家庭幸福感都具有显著影响作用。现在有一项研究想要探究父子沟通和…

企业级信息系统开发讲课笔记3.2 基于Java配置类整合SSM框架实现用户登录

文章目录 零、本节学习目标一、采用MVC架构二、用户登录运行效果三、基于Java配置类整合SSM框架实现用户登录&#xff08;一&#xff09;创建数据库与表1、创建数据库2、创建用户表3、在用户表里插入记录 &#xff08;二&#xff09;创建Maven项目&#xff08;三&#xff09;添…

带你打开GCC的大门

START hi&#xff0c;大家好&#xff01; 今天带大家了解一下GCC。 首先说一句&#xff1a;大写的GCC和小写的gcc不是一个东西呦&#xff0c;下面我们慢慢道来... 1. GCC是什么&#xff1f; GNU Compiler Collection (GCC)是GNU项目开发的编译工具集&#xff0c;支持各种编…

abaqus和ansys做仿真哪个更好

当你要模拟仿真一个机械模型时&#xff0c;通常会听到ABAQUS或ANSYS&#xff0c;最常见的问题是哪个更好&#xff1f;无论是工程设计师还是初学者&#xff0c;通常会问这个问题或类似的问题。在本文中介绍了 Abaqus 与 Ansys&#xff0c;您将了解这些问题的答案。 1-ANSYS&…

数据库8之嵌套查询

上一篇文章讲到连接查询&#xff0c;连接查询就是一个一个去查找相匹配的行&#xff0c;再返回给用户看。当我们数据量少的时候我们用连接查询没有太大问题&#xff0c;可是&#xff0c;当数据量大的时候&#xff0c;连接查询效率显然不高。这个时候我们可以用嵌套查询&#xf…

Oracle跨服务器取数——DBlink 初级使用

前言 一句话解释DBlink是干啥用的 实现跨库访问的可能性. 通过DBlink我们可以在A数据库访问到B数据库中的所有信息,例如我们在加工FDS层表时需要访问ODS层的表,这是就需要跨库访问 一、DBlink的分类 private&#xff1a;用户级别&#xff0c;只有创建该dblink的用户才可以使…

Maven 下载及配置详细步骤

1、Maven 下载 Maven 官网地址:https://maven.apache.org/download.cgi(opens new window) 进入 Maven 官网,点击 archives 下载版本 3.6.2 找到下载的压缩包并解压

传统协议大比拼之IP协议

文章目录 一、引言二、IP协议的基本特点2.1 IP协议的作用和基本功能2.2 地址管理手动分配IP动态主机配置协议(DHCP)网络地址转换(NAT)IPv6 2.2 路由选择RIP(距离向量型的协议)OSPF(链路状态类型协议)BGP(边界网关协议) 2.3 IP协议的特点&#xff1a; 三、IP地址的组成3.1 IP地址…

kong(6):身份认证

1 Basic Auth身份认证配置 Basic Auth插件 # 在服务上配置插件 curl -X POST http://127.0.0.1:8001/services/{service}/plugins --data "namebasic-auth" --data "config.hide_credentialstrue"#在路由上配置插件 curl -X POST http://127.0.0.1:8001/…

上海亚商投顾:沪指全天震荡微跌 新能源赛道股集体反弹

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 大小指数今日走势分化&#xff0c;沪指探底回升小幅下跌&#xff0c;创业板指盘中涨超2%&#xff0c;午后涨幅有所…