深入学习Synchronized各种使用方法

文章目录

  • 前言
  • 一、synchronized关键字通用在下面四个地方:
    • 1.1synchronized修饰实例方法
    • 1.2synchronized修饰静态方法:
    • 1.3synchronized修饰实例方法的代码块
    • 1.4synchronized修饰静态方法的代码块
    • 2.读入数据
  • 二.Sychronized关键特性
    • 2.1互斥
    • 2.2 刷新内存
    • 2.3可重入
  • 三.同步互斥访问
    • 3.1同步互斥访问
    • 3.2Java中实现同步互斥访问的方法
    • 3.3Java中为什么要提供两种同步器(synchronized 和 Lock)
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:
在Java当中synchronized通常是用来标记一个方法或者代码块。在Java当中被synchronized标记的代码或者方法在同一个时刻只能够有一个线程执行被synchronized修饰的方法或者代码块。因此被synchronized修饰的方法或者代码块不会出现数据竞争的情况,也就是说被synchronized修饰的代码块是并发安全的。


提示:以下是本篇文章正文内容,下面案例可供参考

一、synchronized关键字通用在下面四个地方:

1.1synchronized修饰实例方法

public class SynchronizedExample {

    // 实例变量
    private int count = 0;

    // 同步实例方法
    public synchronized void increment() {
        // 在多线程环境中,只有一个线程能够进入这个方法
        count++;
    }

    // 非同步方法
    public void nonSynchronizedMethod() {
        // 这个方法没有使用 synchronized 关键字,多个线程可以同时访问
    }

    public static void main(String[] args) {
        SynchronizedExample example = new SynchronizedExample();

        // 创建多个线程,同时访问同一个实例的 synchronized 方法
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                example.increment();
                System.out.println("Thread 1 - Count: " + example.getCount());
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                example.increment();
                System.out.println("Thread 2 - Count: " + example.getCount());
            }
        });

        // 启动线程
        thread1.start();
        thread2.start();
    }

    // 获取 count 的方法
    public int getCount() {
        return count;
    }
}

increment 方法使用 synchronized 关键字修饰,确保在同一时间内只有一个线程可以进入该方法,防止多线程并发访问导致数据不一致。
nonSynchronizedMethod 方法没有使用 synchronized 关键字,因此多个线程可以同时访问,可能导致竞态条件(race condition)和数据不一致。
main 方法中创建了两个线程,分别调用 increment 方法来递增 count 变量。
getCount 方法用于获取 count 的值。

1.2synchronized修饰静态方法:

当 synchronized 修饰静态方法时,它锁定的是整个类,而不是实例。这意味着在同一时间内只有一个线程能够访问该静态方法,无论创建了多少个类实例。以下是一个使用 synchronized 修饰静态方法的简单示例:

public class SynchronizedStaticExample {

    // 静态变量
    private static int count = 0;

    // 静态同步方法
    public static synchronized void increment() {
        // 在多线程环境中,只有一个线程能够进入这个静态方法
        count++;
    }

    // 非同步方法
    public void nonSynchronizedMethod() {
        // 这个方法没有使用 synchronized 关键字,多个线程可以同时访问
    }

    public static void main(String[] args) {
        SynchronizedStaticExample example1 = new SynchronizedStaticExample();
        SynchronizedStaticExample example2 = new SynchronizedStaticExample();

        // 创建多个线程,同时访问同一个静态方法
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                example1.increment();
                System.out.println("Thread 1 - Count: " + example1.getCount());
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                example2.increment();
                System.out.println("Thread 2 - Count: " + example2.getCount());
            }
        });

        // 启动线程
        thread1.start();
        thread2.start();
    }

    // 获取 count 的方法
    public int getCount() {
        return count;
    }
}

increment 方法使用 synchronized 关键字修饰,确保在同一时间内只有一个线程可以进入该静态方法。
nonSynchronizedMethod 方法没有使用 synchronized 关键字,因此多个线程可以同时访问,可能导致竞态条件(race condition)和数据不一致。
main 方法中创建了两个类实例,但由于 increment 方法是静态的,它们共享同一个静态方法,因此在同一时间内只有一个线程能够访问。
getCount 方法用于获取静态变量 count 的值。

1.3synchronized修饰实例方法的代码块

当 synchronized 修饰实例方法时,它锁定的是对象实例,确保在同一时间内只有一个线程能够访问该方法。如果有多个实例,每个实例都有独立的锁。以下是一个使用 synchronized 修饰实例方法的简单示例:

public class SynchronizedInstanceExample {

    // 实例变量
    private int count = 0;

    // 同步实例方法
    public synchronized void increment() {
        // 在多线程环境中,只有持有当前对象实例锁的线程能够进入这个方法
        count++;
    }

    // 非同步方法
    public void nonSynchronizedMethod() {
        // 这个方法没有使用 synchronized 关键字,多个线程可以同时访问
    }

    public static void main(String[] args) {
        SynchronizedInstanceExample example1 = new SynchronizedInstanceExample();
        SynchronizedInstanceExample example2 = new SynchronizedInstanceExample();

        // 创建多个线程,同时访问同一个实例方法
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                example1.increment();
                System.out.println("Thread 1 - Count: " + example1.getCount());
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                example2.increment();
                System.out.println("Thread 2 - Count: " + example2.getCount());
            }
        });

        // 启动线程
        thread1.start();
        thread2.start();
    }

    // 获取 count 的方法
    public int getCount() {
        return count;
    }
}

increment 方法使用 synchronized 关键字修饰,确保在同一时间内只有持有当前对象实例锁的线程能够进入该方法。
nonSynchronizedMethod 方法没有使用 synchronized 关键字,因此多个线程可以同时访问,可能导致竞态条件(race condition)和数据不一致。
main 方法中创建了两个类实例,每个实例都有独立的锁,因此它们的 increment 方法互不影响。
getCount 方法用于获取实例变量 count 的值

1.4synchronized修饰静态方法的代码块

当 synchronized 修饰静态方法时,它锁定的是类的 Class 对象,确保在同一时间内只有一个线程能够访问该静态方法。以下是一个使用 synchronized 修饰静态方法的简单示例

public class SynchronizedStaticExample {

    // 静态变量
    private static int count = 0;

    // 静态同步方法
    public static synchronized void increment() {
        // 在多线程环境中,只有一个线程能够进入这个静态方法
        count++;
    }

    // 非同步方法
    public void nonSynchronizedMethod() {
        // 这个方法没有使用 synchronized 关键字,多个线程可以同时访问
    }

    public static void main(String[] args) {
        SynchronizedStaticExample example1 = new SynchronizedStaticExample();
        SynchronizedStaticExample example2 = new SynchronizedStaticExample();

        // 创建多个线程,同时访问同一个静态方法
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                SynchronizedStaticExample.increment();
                System.out.println("Thread 1 - Count: " + SynchronizedStaticExample.getCount());
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                SynchronizedStaticExample.increment();
                System.out.println("Thread 2 - Count: " + SynchronizedStaticExample.getCount());
            }
        });

        // 启动线程
        thread1.start();
        thread2.start();
    }

    // 获取 count 的方法
    public static int getCount() {
        return count;
    }
}

increment 方法使用 synchronized 关键字修饰,确保在同一时间内只有一个线程能够进入该静态方法。
nonSynchronizedMethod 方法没有使用 synchronized 关键字,因此多个线程可以同时访问,可能导致竞态条件(race condition)和数据不一致。
main 方法中创建了两个类实例,但由于 increment 方法是静态的,它们共享同一个静态方法,因此在同一时间内只有一个线程能够访问。
getCount 方法用于获取静态变量 count 的值。

2.读入数据

代码如下(示例):

data = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())

该处使用的url网络请求的数据。


二.Sychronized关键特性

2.1互斥

synchronized 会起到互斥效果, 某个线程执行到某个对象的 synchronized 中时, 其他线程如果也执行到同一个对象 synchronized 就会阻塞等待.
进入 synchronized 修饰的代码块, 相当于 加锁
退出 synchronized 修饰的代码块, 相当于 解锁

2.2 刷新内存

synchronized 的工作过程:

  1. 获得互斥锁
  2. 从主内存拷贝变量的最新副本到工作的内存
  3. 执行代码
  4. 将更改后的共享变量的值刷新到主内存
  5. 释放互斥锁

2.3可重入

看到的这个例子很形象
在 Java 中,synchronized 关键字具有可重入性,这意味着如果一个线程已经获得了某个对象的锁,那么它可以再次请求该对象的锁而不会被阻塞。可重入性使得同一个线程在执行一个方法(或代码块)时可以再次进入同步锁定的代码区域,而不会被自己已经持有的锁所阻塞。

这种机制是为了防止由于递归调用或者方法内部调用其他同步方法而导致的死锁。如果不支持可重入性,那么在同一线程中多次调用同步方法,就会因为持有同一个锁而产生死锁。
在这里插入图片描述

public class ReentrantExample {

    public static void main(String[] args) {
        ReentrantExample example = new ReentrantExample();
        example.outerMethod();
    }

    public synchronized void outerMethod() {
        System.out.println("Outer Method");
        innerMethod();
    }

    public synchronized void innerMethod() {
        System.out.println("Inner Method");
    }
}

三.同步互斥访问

3.1同步互斥访问

在多线程编程中,通常会有多个线程同时访问一个资源的情况,同步互斥访问就是在同一时间只能有一个线程对同一资源进行访问。

3.2Java中实现同步互斥访问的方法

同步互斥访问的解决办法是设计一个同步器,对多个线程同时访问同一个共享、可变资源的情况,这个资源我们称之其为临界资源;这种资源可能是: 对象、变量、文件等
同步器采用的方案都是序列化访问临界资源。即在同一时刻,只能有一个线程访问临 界资源。
共享:资源可以由多个线程同时访问。
可变:资源可以在其生命周期内被修改。
Java中目前有 synchronized 和 Lock (ReentrantLock)。

3.3Java中为什么要提供两种同步器(synchronized 和 Lock)

synchronized在1.5版本时的状况:这是因为在jdk1.5版本的时候,jdk官方就提供出了 synchronized 锁,但是在1.5版本的时候,synchronized 锁的加锁方式只有一个,就是通过内部对象Monitor(监视器锁)实现,基于进入与退出Monitor对象实现方法与代码块同步,监视器锁的实现依赖底层操作系统的Mutex lock(互斥锁)实现,它是一个重量级锁性能较低,也就是比较消耗性能。
Lock锁的出现:由于 synchronized 锁的性能不大好,加的锁都是重要级别的锁,涉及到线程之间的状态切换,要从用户态切换到内核态,所以就有一个人设计了Lock锁,在当时,Lock锁的性能要比 synchronized 好很多。
synchronized锁的优化:后来jdk官方就对synchronized锁进行了优化,成了现在这个样子,我感觉真的基本和Lock差不多了。

总结

好了,今天的blog就到此为止,期待大佬们的三连和评论

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

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

相关文章

从零开始学习 JS APL(二):完整指南和实例解析

大家好&#xff01;这里是关于JS APL第二部分的知识点和笔记以及练习题 目录 大家好&#xff01;这里是关于JS APL第二部分的知识点和笔记以及练习题 我们分以下几点来说&#xff1a; 1、事件监听&#xff08;绑定&#xff09;&#xff1a; 目标&#xff1a;能够给 DOM元素…

js实现AES加密解密,简易又全面

常规是直接安装CryptoJS库&#xff0c;但为了减少项目体积&#xff0c;使用这简单的20k文件就ok 一览&#xff1a; 代码中使用的是Pkcs7&#xff0c;但我需要的填充方式是ZeroPadding 所以稍微有修改&#xff1a; q (p.pad {}).ZeroPadding {pad: function (data, blockSi…

文献速递:多模态影像组学文献分享(基于多模式超声的临床放射学诺莫图,用于预测实质性低回声乳腺病变的恶性风险)

文献速递&#xff1a;多模态影像组学文献分享:(基于多模式超声的临床放射学诺莫图&#xff0c;用于预测实质性低回声乳腺病变的恶性风险) 01 文献速递介绍 作为世界上最常见的癌症&#xff0c;乳腺癌对人们的健康和生存构成了严重威胁&#xff08;1&#xff09;。鉴于其高转…

Linux cgroup技术

cgroup 全称是 control group&#xff0c;顾名思义&#xff0c;它是用来做“控制”的。控制什么东西呢&#xff1f;当然是资源的使用了。 cgroup 定义了下面的一系列子系统&#xff0c;每个子系统用于控制某一类资源。 CPU 子系统&#xff0c;主要限制进程的 CPU 使用率。cpu…

DFT(离散傅里叶变换)的通俗理解

本文包含了博主对离散傅里叶变换&#xff0c;负频率&#xff0c;实信号与复信号频谱的理解&#xff0c;如有不妥&#xff0c;欢迎各位批评指正与讨论。 文章目录 DFT的理解信号的频谱实信号的频谱复信号的频谱 DFT的理解 傅里叶变换是一种将信号从时域转换到频域的数学工具。…

通过pipeline配置sonar自动化实现过程解析

这篇文章主要介绍了通过pipeline配置sonar自动化实现过程解析,文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.sonar配置webhooks&#xff0c; 2.url填写jenkins的地址&#xff1a;http://jenkinsurl/sonarqu…

CRC(循环冗余校验)直接计算和查表法

文章目录 CRC概述CRC名词解释宽度 (WIDTH)多项式 &#xff08;POLY&#xff09;初始值 &#xff08;INIT&#xff09;结果异或值 &#xff08;XOROUT&#xff09;输入数据反转&#xff08;REFIN&#xff09;输出数据反转&#xff08;REFOUT&#xff09; CRC手算过程模二加减&am…

1_控制系统总体结构

1、总体结构 控制系统结构图&#xff1a; 黑色块为参数、黄色块为计算模块 1.1 其中参数含义 车辆属性参数&#xff1a; 参数含义 C α f C_{\alpha f} Cαf​自行车模型总轮胎侧偏刚度&#xff08;前轮&#xff09; C α r C_{\alpha r} Cαr​自行车模型总轮胎侧偏刚度&a…

Android wifi disable分析

总体流程 老套路基本不变&#xff1a; WifiSettings 通过 WifiManager 下cmd 给 WifiServiceWifiService 收到cmd后&#xff0c;先完成一部分列行检查&#xff08;如UID的权限、是否airPlayMode等等&#xff09;&#xff0c;之后将cmd下发给到WifiControllerWifiController 收…

云原生的 CI/CD 框架tekton - Trigger(二)

上一篇为大家详细介绍了tekton - pipeline&#xff0c;由于里面涉及到的概念比较多&#xff0c;因此需要好好消化下。同样&#xff0c;今天在特别为大家分享下tekton - Trigger以及案例演示&#xff0c;希望可以给大家提供一种思路哈。 文章目录 1. Tekton Trigger2. 工作流程3…

Learning Memory-guided Normality for Anomaly Detection 论文阅读

Learning Memory-guided Normality for Anomaly Detection 摘要1.介绍2.相关工作3.方法3.1网络架构3.1.1 Encoder and decoder3.1.2 Memory 3.2. Training loss3.3. Abnormality score 4.实验5.总结总结&代码复现&#xff1a; 文章信息&#xff1a; 发表于&#xff1a;cvpr…

忽略python运行出现的大量警告

添加以下代码即可 import warnings warnings.filterwarnings(ignore)

python-ATM机

编写程序&#xff0c;实现一个具有开户、查询、取款、存款、转账、锁定、解锁、退出功能的银行管理系统。 结果展示 1.Main主方法 from zzjmxy.class7.atm import ATM from zzjmxy.class7.manager import Manager # 主面板&#xff0c;实现主要逻辑if __name__"__main__…

【Maven】更新依赖索引

有时候给idea配置完maven仓库信息后&#xff0c;在idea中依然搜索不到仓库中的jar包。这是因为仓库中的jar包索引尚未更新到idea中。这个时候我们就需要更新idea中maven的索引了&#xff0c;具体做法如下&#xff1a; 打开设置----搜索maven----Repositories----选中本地仓库-…

如何搭建eureka-server

在Spring Cloud项目的pom文件中添加eureka-server的starter依赖坐标 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://ma…

指针(3)

如图&#xff0c;这是比较常见的冒泡排序&#xff0c;不过只能对整形数据进行排序。本篇博文主要介绍如何模拟qsort函数实现冒泡排序对任何数据的排序。 如果我们想对任何数据进行排序&#xff0c;我们可以发现&#xff0c;排序的趟数是固定的&#xff0c;我们只需要对比较大…

CFS三层靶机内网渗透

CFS三层靶机内网渗透 一、靶场搭建1.基础参数信息2.靶场搭建2.1网卡配置2.2Target1配置2.2.1 网卡配置2.2.2 Target1 BT配置 2.3Target2配置2.3.1 网卡配置2.3.2 Target2 BT配置 2.4Target3配置 二、内网渗透Target11.1信息收集1.1.1IP收集1.1.2端口收集1.1.3目录收集 1.2 webs…

用 taichi 写个软渲染器

用 taichi 写个软渲染器 What 起点是&#xff1a;可以 setup 一个画布&#xff0c;drawPixel(x, y, color)&#xff0c;然后渲染到 GUI 或者 .png目标是&#xff1a;加载 obj 模型文件和 .tga 贴图文件&#xff0c;并渲染出来使用 taichi 作为 SIMD 加速 backend复现一些 RTR…

【4】PyQt输入框

1. 单行文本输入框 QLineEdit控件可以输入单行文本 from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QVBoxLayout from PyQt5.QtCore import * from PyQt5.QtGui import QIcon import sysdef init_widget(w: QWidget):# 修改窗口标题w.setWindowTitle(单行输…

Python (一) 操作Mysql

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一份大厂面试资料《史上最全大厂面试题》&#xff0c;Springboot、微服务、算法、数据结构、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、数据库等等 …