【JAVA进阶篇教学】第十篇:Java中线程安全、锁讲解

博主打算从0-1讲解下java进阶篇教学,今天教学第十篇:Java中线程安全、锁讲解。 

当涉及到多线程编程时,保证线程安全是至关重要的。线程安全意味着在多个线程访问共享资源时,不会发生数据错乱或不一致的情况。为了实现线程安全,通常需要使用锁机制来控制对共享资源的访问。在Java中,常见的线程安全技术包括使用synchronized关键字,ReentrantLock,读写锁,以及使用volatile关键字。

此文章会长期更新补充完整~~,敬请期待!

目录

一、synchronized 

1.线程不安全实例

2.线程安全实例

3.synchronized修饰代码块

二、ReentrantLock


一、synchronized 

Synchronized是 Java 中的一个关键字,用于实现线程同步。它可以修饰方法或代码块,确保在同一时间只有一个线程可以执行被修饰的代码。
Synchronized是一种互斥锁,也称为悲观锁。它的原理是在执行被修饰的代码之前,线程会尝试获取锁。如果锁已经被其他线程持有,那么当前线程将被阻塞,直到锁被释放。

注意:在实际应用中,需要根据具体情况合理使用Synchronized锁,避免过度使用导致性能下降。

1.线程不安全实例

public class UnsafeCounter {
    private int count = 0;

    public void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

假设有两个线程同时调用 increment() 方法增加计数:

public class UnsafeCounterExample {
    public static void main(String[] args) {
        UnsafeCounter counter = new UnsafeCounter();

        // 创建两个线程并发增加计数
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        thread1.start();
        thread2.start();

        // 等待两个线程执行完成
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 输出最终计数值
        System.out.println("Count: " + counter.getCount()); // 预期结果: 可能小于 2000
    }
}

在这个示例中,由于 increment() 方法没有同步控制,两个线程同时对 count 进行增加操作,可能导致计数不准确。理论上来说,代码应该执行的结果是:2000,但是因为线程不安全,就会导致数据不正确!

第一次运行:

第二次运行:

看到没,结果都会不一样,这要是正式环境中金额的话,那就不得了啦。

2.线程安全实例

使用synchronized修复线程安全问题。

public class SafeCounter {
    private int count = 0;

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

    public synchronized int getCount() {
        return count;
    }
}

在 SafeCounter 类中,我们使用 synchronized 关键字修饰了 increment() 和 getCount() 方法,确保同一时刻只有一个线程可以执行这些方法。

public class SafeCounterExample {
    public static void main(String[] args) {
        SafeCounter counter = new SafeCounter();

        // 创建两个线程并发增加计数
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        thread1.start();
        thread2.start();

        // 等待两个线程执行完成
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 输出最终计数值
        System.out.println("Count: " + counter.getCount()); // 预期结果: 2000
    }
}

在这个示例中,由于使用了 synchronized 关键字修饰方法,保证了线程安全,最终输出的计数值是准确的。

第一次运行:

第二次运行:

可以很清楚的看到,正确的数据是:2000。上面的是synchronized直接修饰了方法,那么接下来使用synchronized来修饰代码块来实现!

3.synchronized修饰代码块

public class SafeCounter {
    private int count = 0;

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

    public int getCount() {
        synchronized (this) {
            return count;
        }
    }
}

在这个示例中,我们使用了 synchronized 关键字来修饰 increment() 和 getCount() 方法中的代码块,同时传入了 this 作为锁对象。这样就确保了在同一时刻只有一个线程可以访问被 synchronized 修饰的代码块,从而实现了线程安全。

public class SafeCounterExample {
    public static void main(String[] args) {
        SafeCounter counter = new SafeCounter();

        // 创建两个线程并发增加计数
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        thread1.start();
        thread2.start();

        // 等待两个线程执行完成
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 输出最终计数值
        System.out.println("Count: " + counter.getCount()); // 预期结果: 2000
    }
}

第一次运行:

第二次运行:

需要注意:

synchronized (this)适用场景:

  1. 当需要在多个线程间同步访问对象实例的非静态方法或成员变量时,可以使用 synchronized (this) 来锁定当前对象实例,确保同一时刻只有一个线程访问对象的方法或成员变量。
  2. 示例:在多线程环境下,如果有多个线程同时操作同一个对象实例的方法或成员变量时,可以使用 synchronized (this) 来确保线程安全。

synchronized (SafeCounter.class)适用场景

  1. 当需要在多个线程间同步访问类的静态方法或静态变量时,可以使用 synchronized (SafeCounter.class) 来锁定类对象,确保同一时刻只有一个线程访问类的静态方法或静态变量。
  2. 示例:在多线程环境下,如果有多个线程同时调用同一个类的静态方法或静态变量时,可以使用 synchronized (SafeCounter.class) 来确保线程安全。

二、ReentrantLock

今天没时间了,明天待续!

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

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

相关文章

问题:幂等性 分布式session

web项目中请求线程到service层的时候远程调用服务之前是串行化执行每个任务都要get阻塞等待任务完成&#xff0c;举例当用户在购物车页面点击去结算就会请求后台toTrade请求获取订单确认的详情数据并渲染到订单详情页&#xff0c;现在在toTrade请求中使用异步任务编排Completab…

微信授权登录02-移动端

目录 ## 前言 1.准备工作 1.1 网站域名 1.2 微信公众号 2.授权登录开发 2.1 前端开发 2.1.1 调起微信授权页面 ## 调起微信授权页面效果图 2.1.2 用户允许授权后回调处理 2.2 后端开发 2.2.1 根据code查询用户信息 2.2.2 自动注册登录 ## 后记 ## 前言 上一篇写…

Nios-II编程入门实验

文章目录 一 Verilog实现流水灯二 Nios实现流水灯2.1 创建项目2.2 SOPC添加模块2.3 SOPC输入输出连接2.4 Generate2.5 软件部分2.6 运行结果 三 Verilog实现串口3.1 代码3.2 引脚3.3 效果 四 Nios2实现串口4.1 sopc硬件设计4.2 top文件4.3 软件代码4.4 实现效果 五 参考资料六 …

nodeJs用ffmpeg直播推流到rtmp服务器上

总结 最近在写直播项目 目前比较重要的点就是推拉流 自己也去了解了一下 ffmpeg FFmpeg 是一个开源项目&#xff0c;它提供了一个跨平台的命令行工具&#xff0c;以及一系列用于处理音频和视频数据的库。FFmpeg 能够执行多种任务&#xff0c;包括解封装、转封装、视频和音频…

Ps各种修改文字超实用方法

介绍 在日常生活中,难免会遇到进行文字修改的ps场景,此时就需要用到比较专业的ps进行文字修改,博主特意整合了多种情况下的文字p图方法进行记录,但是不包含全部情况,只记录日常中常见的情况,也可以解决大部分场景了 原图有可用文字素材 在p图时,我们可以先观察我们要p的图中…

【ARMv8/v9 系统寄存器 5 -- CPU ID 判断寄存器 MPIDR_EL1 使用详细介绍】

文章目录 寄存器名称: MPIDR_EL1寄存器结构:主要功能和用途亲和级别&#xff08;Affinity Levels&#xff09;简介CORE ID 获取函数 在ARMv8-A架构中&#xff0c; MPIDR_EL1寄存器是一个非常重要的系统寄存器&#xff0c;它提供了关于处理器在其物理和逻辑配置中的位置的信息。…

Linux下安装JDK并配置环境变量

一、Oracle官网下载jdk 1、官网地址 https://www.oracle.com/java/technologies/downloads/#java17 2、命令下载 wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz 3、解压 tar -zxvf jdk-17_linux-x64_bin.tar.gz 4、配置环境变量 ec…

webrtc windows 编译,以及peerconnection_client

webrtc windows环境编译&#xff0c;主要参考webrtc官方文档&#xff0c;自备梯子 depot tools 安装 Install depot_tools 因为我用的是windows&#xff0c;这里下载bundle 的安装包&#xff0c;然后直接解压&#xff0c;最后设置到环境变量PATH。 执行gn等命令不报错&…

SQLite .journal 文件

在之前插入大量数据测试的时候&#xff0c;发现在数据库文件同级目录下会产生一个同名.journal的文件&#xff0c;并且不是一直会存在&#xff0c;而是生成一会就会自动删除&#xff0c;然后继续生成继续删除&#xff0c;直到数据插入完成。 初步猜测&#xff0c;应该是类似 re…

rust开发web服务器框架,github排名对比

Rocket Star最多的框架 github仓库地址&#xff1a;GitHub - rwf2/Rocket: A web framework for Rust. Rocket 是一个针对 Rust 的异步 Web 框架&#xff0c;重点关注可用性、安全性、可扩展性和速度。 Axum 异步运行时 githuh仓库地址&#xff1a;GitHub - tokio-rs/axum: …

Unity开发中导弹路径散射的原理与实现

Unity开发中导弹路径散射的原理与实现 前言逻辑原理代码实现导弹自身脚本外部控制脚本 应用效果结语 前言 前面我们学习了导弹的追踪的效果&#xff0c;但是在动画或游戏中&#xff0c;我们经常可以看到导弹发射后的弹道是不规则的&#xff0c;扭扭曲曲的飞行&#xff0c;然后击…

国产操作系统下使用dpkg命令管理软件包 _ 统信 _ 麒麟 _ 中科方德

往期好文&#xff1a;国产操作系统下Chrome的命令行使用 | 统信 | 麒麟 Hello&#xff0c;大家好啊&#xff01;在Linux系统中&#xff0c;dpkg是Debian包管理系统的基础命令工具&#xff0c;它允许用户安装、卸载、查询和管理软件包。在国产操作系统如统信UOS和麒麟KOS、中科方…

精选多个炫酷的数据可视化大屏(含源码),拿走就用~

末尾有链接 演示地址&#xff1a;可视化大数据展示中心 (null.fit) 可视化大数据展示模板-科技语者 (chgskj.cn)

Nginx 基于域名的虚拟主机的配置实验

目录 虚拟主机解释 实验介绍 修改配置文件 一&#xff1a;创建2个虚拟主机的网页根目录 二&#xff1a;修改2个虚拟主机的首页的内容 三&#xff1a;真实机器添加域名解析记录 四&#xff1a;测试 虚拟主机解释 Nginx的虚拟主机是指一台服务器上同时托管多个网站的能力。…

Mysql 日志(redolog, binlog, undoLog)

重做日志-redolog 是什么 innoDB存储引擎层面的日志&#xff0c;它的作用是当 数据更新过程中数据库发生异常导致提交的记录丢失 为什么 mysql的基本存储结构是页&#xff08;记录都在页里面&#xff09;&#xff0c;所以更新语句时&#xff0c;mysql需要先把要更新的语句找…

厉害了!12秒将百万数据通过EasyExcel导入MySQL数据库中

一、写在开头 我们在上一篇文章中提到了通过EasyExcel处理Mysql百万数据的导入功能&#xff08;一键看原文&#xff09;&#xff0c;当时我们经过测试数据的反复测验&#xff0c;100万条放在excel中的数据&#xff0c;4个字段的情况下&#xff0c;导入数据库&#xff0c;平均耗…

LibreNMS简介

目录 1 LibreNMS简单介绍1.1 LibreNMS介绍 2 安装2.1 Ubuntu安装1、安装依赖2、添加 librenms 用户3、下载 LibreNMS4、设置权限5、安装 PHP 依赖项6、设置时区7、配置 MariaDB8、配置 PHP-FPM9、配置 Web 服务器10、启用 lnms 命令11、配置 snmpd12、cron13、启用调度程序14、…

[Flutter GetX使用] Getx路由和状态管理-GetController使用过程中的踩坑记录

文章目录 问题 - Get.find() 报错!原因总结A:路由和控制器设计a1:项目中的Get路由aa1.项目路由结构aa2.本项目路由的注意点: B: GetController的冷知识C: 总结来看D: 一些参考资料 问题 - Get.find() 报错! 刚接触Getx, 遇到 Get.find()确找不到, 进而报错的问题, 一时间有点没…

AI算法-高数4-偏导数(理解梯度下降算法基础)

宋浩老师&#xff1a;6.3 偏导数_哔哩哔哩_bilibili 示例&#xff1a; 几何意义&#xff1a;

nodejs复习笔记

最近在复习nodejs&#xff0c;整理了一些笔记来记录和分享。 非常惭愧&#xff0c;我之前关于nodejs学习的一篇文章《nodejs全栈开发学习笔记》已经是2019年6月份的时候了&#xff0c;大概浏览了一下&#xff0c;发现当时很多不明白的地方&#xff0c;现在通过复习&#xff0c…