Synchronized锁的使用

news2024/12/25 12:40:38

前言:大家好,我是小威,24届毕业生,在一家满意的公司实习。本篇文章是关于并发编程中Synchronized锁的用法知识记录,由于篇幅原因,核心原理知识下篇记录。
本篇文章记录的基础知识,适合在学Java的小白,也适合复习中,面试中的大佬🤩🤩。
如果文章有什么需要改进的地方还请大佬不吝赐教👏👏。
小威在此先感谢各位大佬啦~~🤞🤞
在这里插入图片描述

🏠个人主页:小威要向诸佬学习呀
🧑个人简介:大家好,我是小威,一个想要与大家共同进步的男人😉😉
目前状况🎉:24届毕业生,在一家满意的公司实习👏👏

🎁如果大佬在准备面试,可以使用我找实习前用的刷题神器哦刷题神器点这里哟
💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,我亲爱的大佬😘

以下正文开始
在这里插入图片描述

文章目录

  • Synchronized的用法
    • 同步示例方法
    • 同步静态方法
    • 同步代码块

Synchronized的用法

在多线程并发问题中,常用Synchronized锁解决问题。Synchronized锁通常用于同步示例方法,同步静态方法,同步代码块等。

同步示例方法

我们可能自己使用过在方法前加Synchronized锁修饰,在多线程并发同时调用同一个实例化对象时,如果这个方法加上了Synchronized锁,那么也是线程安全的。
举个栗子:

package Thread;

import java.util.stream.IntStream;

public class ThreadTest {
    private Long count=0L;
    public void incrementCount(){
        count++;
    }
    public Long execute() throws InterruptedException {
        Thread thread1=new Thread(()->{
            IntStream.range(0,1000).forEach((i)->incrementCount());//线程1循环1000次
        });
        Thread thread2=new Thread(()->{
            IntStream.range(0,1000).forEach((i)->incrementCount());//线程2循环1000次
        });
        thread1.start();//开启线程
        thread2.start();
        thread1.join();//等待线程1和线程2执行完毕
        thread2.join();
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadTest threadTest=new ThreadTest();
        Long count = threadTest.execute();
        System.out.println(count);
    }
}

在上面的程序中,count变量为成员变量,在多线程同时使用时极大可能会发生错误,在前面也讲到过count++包含三个步骤:1.将变量count从主内存中加载到CPU的寄存器中;2.在CPU的寄存器中执行count++或++count的操作;3.将运算的count++的结果写入缓存或内存中。两个线程都会更新count的值到内存中,当其中一个线程再从内存中读取数据时,可能读到的成员变量会与当前的变量不一致,从而使得最终count的结果不为2000,因此会发生错误。

如何能解决这种错误?就是为incrementCount方法加锁:

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

这样就能保证所得到的count最终值为2000了。
在这里插入图片描述

同步静态方法

当一个类的某个静态方法加了synchronized锁时,就相当于给这个类的class对象加锁。所以无论创建多少个当前类的对象调用这个被synchronized锁修饰的静态方法时,都是线程安全的。
如上面的例子,修改如下:

package Thread;

import java.util.stream.IntStream;

public class ThreadTest {
    private static Long count=0L;
    public static synchronized void incrementCount(){
        count++;
    }
    public static Long execute() throws InterruptedException {
        Thread thread1=new Thread(()->{
            IntStream.range(0,1000).forEach((i)->incrementCount());
        });
        Thread thread2=new Thread(()->{
            IntStream.range(0,1000).forEach((i)->incrementCount());
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadTest threadTest=new ThreadTest();
        Long count = threadTest.execute();
        System.out.println(count);
    }
}

因此,当多个线程并发执行调用被synchronized锁修饰的静态方法时,这个静态方法是线程安全的。
在这里插入图片描述

同步代码块

前面提到加了synchronized锁的方法在多线程并发条件下是线程安全的,但是在执行业务逻辑过多的代码块时,可能会影响程序的执行效率。对于此时,可以把一个方法分成多个小的临界区。
举个栗子:

    private Long count1=0L;
    private Long count2=0L;
    public synchronized void incrementCount(){
        count1++;
        count2++;
    }

在上面的代码中,count1和count2为两个不同的自增操作,因此对于count1和count2来说是两个不同的临界区资源。当一个线程进入incrementCount方法中时,会对整个方法进行加锁,在对count1进行自增操作时,也会占用count2的资源,相当于占用全部的资源。只有等到这个线程执行完count1++和count2++的操作时,释放锁时,其它线程才能拿到锁资源进入incrementCount方法。

但是这样会影响程序的性能。因为count1++和count2++为两个互不影响的两个临界区资源,当线程拿到锁,会占用两个资源,使得临界区资源进行闲置等待,因此可以优化代码,让synchronized锁修饰代码块。

修改后的代码:

    private Long count1=0L;
    private Long count2=0L;
    public Object count1Lock=new Object();
    public Object count2Lock=new Object();
    public void incrementCount(){
        synchronized (count1Lock){
            count1++;
        }
        synchronized (count2Lock){
            count2++;
        }
    }

上面代码中,对count1和count2分别建立了对象锁count1Lock和count2Lock,而没有对incrementCount加锁,意为当一个线程进入incrementCount方法时,其他线程也能进入此方法,当线程1拿到count1Lock对象锁时,不影响线程2拿到count2Lock对象锁来对count2执行自增操作。

这样既提高了程序的执行效率,同时,由于临界区资源都加了锁,incrementCount方法也是线程安全的。

本篇文章就分享到这里了,后续将会分享Synchronized锁的核心原理内容,感谢大佬认真读完支持咯 ~
在这里插入图片描述

文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起讨论🍻
希望能和诸佬们一起努力,今后进入到心仪的公司
再次感谢各位小伙伴儿们的支持🤞

在这里插入图片描述

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

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

相关文章

进程的基本概念(操作系统)

目录 一、程序的顺序执行及其特征 二、程序的并发执行及其特征 三、进程的特征与状态 1、进程的定义和特征 2、进程的三种基本状态 3、进程的三种基本状态的转换 4、 挂起状态 四、进程控制块(PCB) 1. PCB作用: PCB是进程存在的唯一…

【力扣】正则表达式匹配--回溯法解剖

题目:10.正则表达式匹配 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符 * 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。 示…

maven配置阿里镜像,解决IDEA配置maven恢复默认配置问题

文章目录1.三个IDEA配置说明2.拷贝与修改settings.xml2.1 找到IDEA的mave配置文件settings.xml位置2.2 拷贝IDEA的settings.xml到.m2目录下2.3 打开settings.xml,配置本地库LocalRepository的路径2.4 删除默认镜像配置,配置阿里镜像2.5 保存文件3.验证是…

面试时,MySQL这些基础知识你回答的出来吗?

目录 【一】前言 【二】MySQL的并发控制 【三】数据库的事务 【四】隔离级别 【五】死锁 【六】存储引擎 6.1 InnoDB存储引擎 6.2 MyISAM存储引擎 【七】总结 【一】前言 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,属于Oracle…

一文就读懂RPC远程调用核心原理

rpc核心原理 什么是rpc? rpc的全称是Remote Procedure Call,即远程过程调用,是分布式系统的常用通信方法。 Remote,简单来说的话就是两个不同的服务之间,两个服务肯定是两个不同的进程。因此,我们就从跨进…

【微服务】微服务万字实战,带你了解工程原理

微服务实战1、前期准备1.1 技术选型1.2 模块设计1.3 微服务调用2、创建父工程3、创建基础模块3.1 导入依赖3.2 创建实体类4、创建用户微服务4.1 创建shop-user模块4.2 用户微服务启动类4.3 创建配置文件5、创建商品微服务5.1 创建shop_product模块5.2 商品微服务启动类5.3 创建…

刷题日记【第六篇】-笔试必刷题【最近公共祖先+求最大连续bit数+二进制插入+查找组成一个偶数最接近的两个素数】

目录 选择题模块 1.下面哪个标识符是合法的?(D) 2.以下描述正确的是(B) 3.下列程序的运行结果(B) 4.下列关于容器集合类的说法正确的是?(C) 5.ArrayList…

【MySQL进阶】深入理解InnoDB记录结构

【MySQL进阶】深入理解InnoDB记录结构 参考资料:《MySQL是怎么运行的:从根儿上理解MySQL》。 前言: 我们一般使用的MySQL关系型数据库,更是经典中的经典,虽说MySQL已经非常成熟,但对于MySQL的掌握程度&a…

腾讯Java888道高频面试真题笔记+Java面试宝典

这多半年你是否达到了你年初定的目标,今年企业招聘要求也是更加的严格,对于低学历,以及技术实力不过关的更是雪上加霜。也是由于种种缘由,从5月开始就一直有粉丝私信要博主整理一些干货来帮助他们提升下自己,为了响应粉丝要求&…

Non-Autoregressive Coarse-to-Fine Video Captioning【论文阅读】

Non-Autoregressive Coarse-to-Fine Video Captioning 发表:AAAI 2021idea:(1)针对推理阶段不能并行,推理效率低的问题使用一种双向解码(在bert中不使用sequence mask)。(2&#xf…

基于QD求解法的二分类SVM仿真

目录 1.算法概述 2.部分程序 3.算法部分仿真结果图 4.完整程序获取 CSDN用户:我爱C编程 CSDN主页:https://blog.csdn.net/hlayumi1234567?typeblog 擅长技术:智能优化,路径规划,通信信号,图像处理&…

【数据结构与算法分析】0基础带你学数据结构与算法分析06--树(TREE)

目录 前言 树的属性 树的实现 树的遍历与应用 深度有限遍历 (DFS) 广度优先遍历 (BFS) Not all roots are buried down in the ground, some are at the top of a tree. — Jinvirle 前言 Tree 是一些结点的集合,这个集合可以是空集;若不是空集…

【模型训练】YOLOv7行人检测

YOLOv7行人检测 1、YOLOv7算法行人检测模型训练2、YOLOv7模型模型评估3、模型和数据集下载1、本项目采用YOLOv7算法实现对行人的检测和识别,在一万多张行人检测数据集中训练得到,我们训练了YOLOv7模型,经评估我们得出了各个模型的评价指标; 2、目标类别数:1 ;类别名:pers…

笔试强训第15天(手套+ 查找输入整数二进制中1的个数)

选择 C barfoob_bar new B 会先创建一个B类对象,B类对象的构造需要调用B的构造函数,从而调用A的构造函数。A的构造函数中调用了 bar()函数,该函数虽然重写了,但这里不构成多态调用。因为虚表中的函数指针是在构造函数的初始化列表…

爱上源码,重学Spring IoC深入

回答: 我们为什么要学习源码? 1、知其然知其所以然 2、站在巨人的肩膀上,提高自己的编码水平 3、应付面试1.1 Spring源码阅读小技巧 1、类层次藏得太深,不要一个类一个类的去看,遇到方法该进就大胆的进 2、更不要一行…

【3D目标检测】SECOND: Sparsely Embedded Convolutional Detection

目录概述细节网络结构稀疏卷积方向分类损失函数概述 首先,本文是基于点云,并且将点云处理成体素的3D目标检测网络,提出的SECOND可以看做是VoxelNet的升级版。 提出动机与贡献 VoxelNet计算量比较大,速度比较慢(训练和…

第二节:数据类型与变量【java】

目录 📃前言 📗1.数据类型 📕2. 变量 2.1 变量概念 2.2 语法格式 📙3.整型变量 3.1 整型变量 3.2 长整型变量 3.3 短整型变量 3.4 字节型变量 📘4.浮点型变量 4.1 双精度浮点型 4.2 单精度浮点型 &#…

[SpringBoot] AOP-AspectJ 切面技术

✨✨个人主页:沫洺的主页 📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏 📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专…

python的编译器与解释器

作者介绍: 🐥作者:小刘在C站 👆每天分享课堂笔记,一起努力,共赴美好人生 🍁夕阳下,是最美的绽放 目录 一.为什么会有编译器和解释器 二.编译器和解释器的区别 三.python解释器种类…

RK3399应用开发 | 移植libdrm到rk3399开发板(2.4.113)

一、下载源码 下载地址:https://dri.freedesktop.org/libdrm/。 这里我下载最新的2.4.113版本: wget https://dri.freedesktop.org/libdrm/libdrm-2.4.113.tar.xz解压: xz -d libdrm-2.4.113.tar.xz tar -xf libdrm-2.4.113.tar二、编译环境安装 1. 更新python ubuntu安…