Java各种锁

news2024/12/23 23:29:39

目录

一、读写锁(ReentrantReadWriteLock)

二、非公平锁(synchronized/ReentrantLock)

三、可重入锁/递归锁(synchronized/ReentrantLock)

四、自旋锁(spinlock)

五、乐观锁/悲观锁

六、死锁

1、死锁代码

 2、死锁的检测(jps -l 与 jstack 进程号)


本文通过学习:周阳老师-尚硅谷Java大厂面试题第二季 总结的锁相关的笔记

一、读写锁(ReentrantReadWriteLock)

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class MyCache {
    private volatile Map<String, Object> map = new HashMap<>();//volatile保证可见性
    private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void put(String key, Object value) {
        rwLock.writeLock().lock();//写锁创建
        try {
            System.out.println(Thread.currentThread().getName() + "\t 正在写入:" + key);
            try {
                // 模拟网络拥堵,延迟0.3秒
                TimeUnit.MILLISECONDS.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "\t 写入完成");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rwLock.writeLock().unlock();//写锁释放
        }
    }

    public void get(String key) {
        rwLock.readLock().lock();//读锁创建
        try {
            System.out.println(Thread.currentThread().getName() + "\t 正在读取:");
            try {
                TimeUnit.MILLISECONDS.sleep(300);//模拟网络拥堵,延迟0.3秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Object value = map.get(key);
            System.out.println(Thread.currentThread().getName() + "\t 读取完成:" + value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rwLock.readLock().unlock();//读锁释放
        }
    }

    public void clean() {
        map.clear();//清空缓存
    }
}

public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache myCache = new MyCache();

        for (int i = 1; i <= 5; i++) {//5个线程写
            final int tempInt = i;//final
            new Thread(() -> {
                myCache.put(tempInt + "", tempInt +  "");
            }, String.valueOf(i)).start();
        }

        for (int i = 1; i <= 5; i++) {//5个线程读
            final int tempInt = i;//final
            new Thread(() -> {
                myCache.get(tempInt + "");
            }, String.valueOf(i)).start();
        }
    }
}

二、非公平锁(synchronized/ReentrantLock)

定义区别
非公平锁多个线程获取锁的顺序,并不是按照申请锁的顺序,有可能申请的线程比先申请的线程优先获取锁,在高并发环境下,有可能造成优先级翻转,或者饥饿的线程(也就是某个线程一直得不到锁)比较粗鲁,上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式
公平锁多个线程按照申请锁的顺序来获取锁,类似于排队买饭,先来后到,先来先服务,就是公平的,也就是队列很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列中的第一个,就占用锁,否者就会加入到等待队列中,以后安装FIFO的规则从队列中取到自己
  • synchronized是非公平锁
  • ReentrantLock默认非公平锁
    • Lock lock = new ReentrantLock(true);//默认false非公平锁,true公平锁

三、可重入锁/递归锁(synchronized/ReentrantLock)

synchronized可重入锁

ReentrantLock可重入锁

class MySynchronized {
    public synchronized void sendSMS() throws Exception{//发短信
        System.out.println(Thread.currentThread().getName() + "\t invoked sendSMS()");
        sendEmail();//同步方法中调用另外一个同步方法
    }

    public synchronized void sendEmail() throws Exception{//发邮件
        System.out.println(Thread.currentThread().getId() + "\t invoked sendEmail()");
    }
}
public class MyDemo {
    public static void main(String[] args) {
        MySynchronized mySynchronized = new MySynchronized();
        new Thread(() -> {
            try {
                mySynchronized.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "t1").start();

        new Thread(() -> {
            try {
                mySynchronized.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "t2").start();
    }
}
/**
t1  invoked sendSMS()
t1  invoked sendEmail()
t2  invoked sendSMS()
t2  invoked sendEmail()
*/
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class MyReentrantLock implements Runnable{
    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        method1();
    }

    public void method1() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() 
            + "\t exe method1");
            method2();
        } finally {
            lock.unlock();
        }
    }

    public void method2() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() 
            + "\t exe method2");
        } finally {
            lock.unlock();
        }
    }
}
public class ReenterLockDemo {
    public static void main(String[] args) {
        MyReentrantLock myReentrantLock = new MyReentrantLock();
        Thread t1 = new Thread(myReentrantLock, "t1");
        Thread t2 = new Thread(myReentrantLock, "t2");
        t1.start();
        t2.start();
    }
}
/**
t1  exe method1
t1  exe method2
t2  exe method1
t2  exe method2
*/

四、自旋锁(spinlock)

public class SpinLockDemo {
    // 现在的泛型装的是Thread,原子引用线程
    AtomicReference<Thread>  atomicReference = new AtomicReference<>();

    public void myLock() {//加锁
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName() + "\t come in ");
        //开始自旋,期望值是null,更新值是当前线程,如果是null,则更新为当前线程,否者自旋
        while(!atomicReference.compareAndSet(null, thread)) {
        }
    }

    public void myUnLock() {//解锁
        Thread thread = Thread.currentThread();
        //自己用完了后,把atomicReference变成null
        atomicReference.compareAndSet(thread, null);
        System.out.println(Thread.currentThread().getName() + "\t invoked myUnlock()");
    }

    public static void main(String[] args) {
        SpinLockDemo spinLockDemo = new SpinLockDemo();
        new Thread(() -> {
            spinLockDemo.myLock();//加锁
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            spinLockDemo.myUnLock();//释放锁
        }, "t1").start();

        //1秒后,启动t2线程占用锁
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            spinLockDemo.myLock();//加锁
            spinLockDemo.myUnLock();//释放锁
        }, "t2").start();
    }
}
/**
t1   come in
.....五秒后.....
t1   invoked myUnlock()
t2   come in 
t2   invoked myUnlock()
*/

首先输出的是 t1 come in,然后1秒后,t2线程启动,发现锁被t1占有,然后不断执行compareAndSet方法,来进行比较,直到t1释放锁后,也就是5秒后,t2成功获取到锁,然后释放
 

五、乐观锁/悲观锁

1、MybatisPlus使用乐观锁的3步走
step1、在数据库增加version字段,默认为1
step2、在实体类增加对应的字段
    @Version
    private Integer version;
step3、注册乐观锁,在MybatisPlusConfig中配置
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

2、悲观锁

六、死锁

1、死锁代码

import java.util.concurrent.TimeUnit;

class HoldLockThread implements Runnable{
    private String lockA;
    private String lockB;

    public HoldLockThread(String lockA, String lockB) {
        this.lockA = lockA;
        this.lockB = lockB;
    }

    @Override
    public void run() {
        synchronized (lockA) {
            System.out.println(Thread.currentThread().getName() 
            + "\t 自己持有" + lockA + "\t 尝试获取:" + lockB);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (lockB) {
                System.out.println(Thread.currentThread().getName() 
                + "\t 自己持有" + lockB + "\t 尝试获取:" + lockA);
            }
        }
    }
}

public class DeadLockDemo {
    public static void main(String[] args) {
        String lockA = "lockA";
        String lockB = "lockB";
        new Thread(new HoldLockThread(lockA, lockB), "t1").start();
        new Thread(new HoldLockThread(lockB, lockA), "t2").start();
    }
}
/**
t1   自己持有lockA   尝试获取:lockB
t2   自己持有lockB   尝试获取:lockA
*/

 2、死锁的检测(jps -l 与 jstack 进程号)

step1、jps -l

step2、jstack 7560   #后面参数是jps输出的该类的pid

查看最后一行,我们看到 Found 1 deadlock,即存在一个死锁 

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

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

相关文章

Spring——Spring介绍和IOC相关概念

Spring是以Spring Framework为核心&#xff0c;其余的例如Spring MVC&#xff0c; Spring Cloud&#xff0c;Spring Data&#xff0c;Spring Security SpringBoot的基础都是Spring Framework。 Spring Boot可以在简化开发的基础上加速开发。 Spring Cloud分布式开发 Spring有…

SAP MM学习笔记6-SAP要怎么学

SAP还是很复杂的&#xff0c;学习之前&#xff0c;了解学习技巧很重要。 根据前辈经验&#xff0c;SAP学习技巧大致总结为如下三个&#xff0c;供大家参考。 1&#xff0c;忘了自己技术者的身份&#xff0c;控制追求技术细节的冲动 软件行业经常听到一句话&#xff0c;什么都…

Python进阶-----面对对象6.0(绑定方法[类方法、静态方法]与内置方法)

目录 前言&#xff1a; 1.绑定方法 &#xff08;1&#xff09;实例方法 &#xff08;2&#xff09;类方法 &#xff08;3&#xff09;静态方法 2.类型检测 &#xff08;1&#xff09;issubclass() 函数 &#xff08;2&#xff09;isinstance() 函数 3.内置方法&#xf…

【Verilog】——赋值语句、结构语句、块语句

目录 1.常用语句 2.块语句 1.顺序块 2.并行块 ​ 3.结构语句 1.always 2.initial 4.赋值语句 1.非阻塞赋值 2.阻塞赋值 3.非阻塞赋值和阻塞赋值的区别 4.深入理解阻塞赋值和非阻塞赋值 声明信号的时候统一大数在高位&#xff0c;小数在低位 比如&#xff1a;reg [3:…

多线程篇之8锁问题、字节码看Synchronized

八锁问题 ①. 标准访问有ab两个线程,请问先打印邮件还是短信 ②. sendEmail方法暂停3秒钟,请问先打印邮件还是短信 ③. 新增一个普通的hello方法,请问先打印邮件还是hello ④. 有两部手机,请问先打印邮件还是短信 ⑤. 两个静态同步方法,同1部手机,请问先打印邮件还是短信 ⑥. …

【数据库系列】MQSQL历史数据分区

互联网行业企业都倾向于mysql数据库&#xff0c;虽说mysql单表能支持亿级别的数据量&#xff0c;加上索引优化下查询速度&#xff0c;勉强能使用&#xff0c;但是对于追求性能和效率的互联网企业&#xff0c;这是远远不够的。Mysql数据库单表数据量到达500万左右&#xff0c;达…

第四讲:如何将本地代码与服务器代码保持实时同步

一、前言 在我们进行 Ambari 二次开发时,通常会先在服务器上部署一套可以使用的 Ambari 环境。 二次开发,就肯定是要改动代码的,我们不能老是在服务器上用vim编辑文件,那样效率太低,始终不是长久之计。 所以我们需要在本地打开我们的Ambari源码项目,比如用idea工具,可…

【电子学会】2022年12月图形化二级 -- 绘制风车

绘制风车 1. 准备工作 &#xff08;1&#xff09;隐藏默认的小猫角色&#xff1b; &#xff08;2&#xff09;选择背景&#xff1a;“Xy-grid”。 2. 功能实现 &#xff08;1&#xff09;小猫角色的初始位置为(x:0,y:0)&#xff1b; &#xff08;2&#xff09;线条粗细为…

实验4 设计模式实验3

实验内容: 1. 某软件公司为新开发的智能手机控制与管理软件提供了一键备份功能,通 过该功能可以将原本存储在手机中的通信录、短信、照片、歌曲等资料一次性全 部拷贝到移动存储介质(例如MMC 卡或SD 卡)中。在实现过程中需要与多个 已有的类进行交互,例如通讯录管理类、短信…

黑马Spring学习笔记(四)——面向切面编程AOP

目录 一、AOP简介 二、AOP核心概念 三、AOP入门案例 四、AOP配置管理 4.1 AOP切入点表达式 4.1.1 语法格式 4.2.2 通配符 4.2.3 书写技巧 4.2 AOP通知类型 4.2.1 前置、后置、返回后、抛出异常后获取参数 4.2.2 环绕通知 一、AOP简介 AOP(Aspect Oriented Pro…

【IoT】创业成功不可或缺的两个因素:能力和趋势

今天就来谈谈能力和趋势究竟哪个更重要的问题。 在谈成功的十大要素时&#xff0c;我曾经讲到&#xff1a; 一命、二运、三风水&#xff0c;这三个要素几乎不涉及任何个人的努力。 而趋势跟这三个要素又是息息相关的&#xff0c;这也类似雷军所说的飞猪理论。 只要风足够大&…

Centos7(阿里云)_安装Mysql8.0

1.安装MySQL 新人可以试用一个月的阿里云&#xff0c;centos7的 一开始可能确实会自带mariadb&#xff0c;所以可以在网上随便找个教程开始尝试安装MySQL&#xff0c;当然大概率出错&#xff0c;然后此时你的rpm下面已经有了一个版本的mysql安装包。 以我为例&#xff0c;随便…

Windows下jdk安装与卸载-超详细的图文教程

jdk安装 下载jdk 由于现在主流就是jdk1.8&#xff0c;所以这里就下载jdk1.8进行演示。官方下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#java8-windows。 官方下载需要注册oracle账号&#xff0c;国内下载有可能速度慢&#xff0c;若不想注册账…

【Linux】P5 实用快捷键 以及 下载安装指令

Linux实用快捷键与下载安装实用快捷键强制停止退出账户 / 环境查看历史命令光标移动快捷键清屏下载安装命令CentOS - yumUbunto - apt实用快捷键 强制停止 CTRL C当程序陷入死循环或者执行错误&#xff0c;可通过该命令强制停止 当程序输入很长但是发现错误&#xff0c;不想…

PDF 解析格式化输出 API 数据接口

PDF 解析格式化输出 API 数据接口 支持输出 TEXT HTML XML TAG&#xff0c;多种格式输出&#xff0c;超精准识别率。 1. 产品功能 通用的识别接口&#xff0c; 支持标准 PDF 文件解析&#xff1b;多种格式输出&#xff0c;支持 TEXT HTML XML TAG&#xff1b;HTML 包含完美排…

蒙特卡洛树搜索(MTCS)

一、目标 一种启发式的搜索算法&#xff0c;在搜索空间巨大的场景下比较有效 算法完成后得到一棵树&#xff0c;这棵树可以实现&#xff1a;给定一个游戏状态&#xff0c;直接选择最佳的下一步 二、算法四阶段 1、选择&#xff08;Selection&#xff09; 父节点选择UCB值最…

【ONE·C || 文件操作】

总言 C语言&#xff1a;文件操作。    文章目录总言1、文件是什么&#xff1f;为什么需要文件&#xff1f;1.1、为什么需要文件&#xff1f;1.2、文件是什么&#xff1f;2、文件的打开与关闭2.1、文件指针2.2、文件打开和关闭&#xff1a;fopen、fclose2.3、文件使用方式3、文…

windows下go安装并使用protobuf

go使用protobuf的过程以及可能出现的问题1. 下载proto windows版本并安装2. 安装protoc-gen-go3. proto文件转go文件报错protoc-gen-go: unable to determine go import path for "xxxx.proto"4. 生成的go文件中google.golang.org/protobuf/reflect/protoreflect依赖…

Zookeeper3.5.7版本——客户端命令行操作(znode 节点数据信息)

目录一、命令行语法二、znode 节点数据信息2.1、查看当前znode中所包含的内容2.2、查看当前节点详细数据2.3、节点详细数据解释一、命令行语法 命令行语法列表 命令基本语法功能描述help显示所有操作命令ls path使用 ls 命令来查看当前 znode 的子节点 [可监听]-w 监听子节点变…

粒子群优化最小二乘支持向量机SVM回归分析,pso-lssvm回归预测

目录 支持向量机SVM的详细原理 SVM的定义 SVM理论 SVM应用实例,粒子群优化最小二乘支持向量机SVM回归分析 代码 结果分析 展望 支持向量机SVM的详细原理 SVM的定义 支持向量机(support vector machines, SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大…