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

news2025/2/23 3:01:31

博主打算从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

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

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

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

相关文章

【Linux】常用基本指令

目录 食用说明 用户管理 whoami/who clear tree 目录结构和路径 pwd ls 文件 隐藏文件 常用选项 cd 家目录、根目录、绝对路径和相对路径 touch 常用选项 mkdir rmdir/rm man cp mv cat nano echo 输出重定向 > 输入重定向 < more/less head/…

comfyui安装deforum启动不了,多半是ffmpeg的问题

如果报错中出现imageio 和 ffmpeg 的字样&#xff0c;去装requirement也没啥用 这里最好到cmd中&#xff0c;进入comfyui的python环境&#xff0c;运行以下两句&#xff1a; import imageio imageio.plugins.ffmpeg.download() 图例&#xff1a; 如果节点不报错了&#xff0…

嵌入式引脚工作模式

一.引脚工作模式的基本概念 引脚的工作模式通常包括输入模式、输出模式和双向模式&#xff1a; 输入模式&#xff1a;引脚设置为输入模式时&#xff0c;可以接收外部信号或触发器的信号。这种模式通常用于读取传感器数据、接收外部设备的信号等。 输出模式&#xff1a;引脚设…

Lora基础炼丹学习笔记

1、收集数据集 20-30张人物各个角度、各个姿势的图片 2、图片预处理 裁剪 打标签 裁剪必须也要512 * 512 &#xff0c;因为sd1.5就是用这个尺寸训练的&#xff0c;可以使用后期处理 打标可以勾选这个&#xff0c;Deepbooru对二次元画风更友好 打标也可以使用wb14-tagger的…

openssl 生成证书步骤

本地测试RSA非对称加密功能时&#xff0c;需要用到签名证书。本文记录作者使用openssl本地生成证书的步骤&#xff0c;并没有深入研究openssl&#xff0c;难免会有错误&#xff0c;欢迎指出&#xff01;&#xff01;&#xff01; 生成证书标准流程&#xff1a; 1、生成私钥&am…

关于ssrf

首先&#xff0c;先介绍一下ssrf。ssrf即服务器端请求伪造&#xff0c;是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统。而且因为请求是由服务端发起的&#xff0c;所以服务端能请求到与自身相连而与…

计算机网络——应用层协议(2:http协议)

在这篇文章中自定义应用层协议&#xff0c;我曾介绍了应用层协议中需要我们开发人员自行制定应用层协议&#xff0c;而应用层协议又离不开结构化字段以及序列化和反序列化还有报头的封装。而在今天&#xff0c;我们有一种应用层协议是我们几乎人人都接触过的协议&#xff0c;它…

暗区突围国际服pc端海外版新手前期如何赚钱 暗区突围新手教学

暗区突围国际服pc端海外版新手前期如何赚钱 暗区突围新手教学 暗区突围是一款极为惊险的射击游戏&#xff0c;让玩家充分感受紧张激烈的战斗以及获取财富的过程。但是有许多新手玩家是不会在游戏里赚钱的&#xff0c;也会在赚钱过程中遇到很多问题&#xff0c;我将在这篇文章…

PGP加密技术:保护信息安全的利器

随着数字化时代的到来&#xff0c;个人和企业对信息安全的需求日益增长。PGP&#xff08;Pretty Good Privacy&#xff09;加密技术作为一项强大的加密工具&#xff0c;为保护敏感数据提供了一种有效的方法。本文将探讨PGP加密技术的基本原理、应用场景以及其在现代信息安全中的…

IDEA - java.lang.OutOfMemoryError: Java heap space / insufficient memory

IDEA 第一次运行项目时&#xff0c;会报如题错误&#xff0c;解决办法是&#xff1a; 将图示部分由默认的 700 改为 2048。

PPT弹簧画法

1. 插入两个圆 2. 使用Lvyhtools的形状-位置分布-圆形阵列 注意&#xff1a;阵列中心要点击文字后才能选择 3. 删除中心的圆&#xff0c;使用Onekey10的原位复制&#xff0c;可以多次&#xff1b; 4. 右击图像选择设置形状格式-线条&#xff08;无线条&#xff09; 5. 找到第二…

云HIS源码,基于云计算的医院临床信息系统(有应用案列)

云HIS全套商业源码&#xff0c;基于云计算的医院临床信息系统 提供预约挂号、门急诊收费、门诊医生站、护士工作站、药房药库管理、电子病历、住院医生站、住院护士工作站、住院登记结算、出院管理、病案管理、医药价格管理、财务管理、统计查询、会员管理等业务及管理功能。 …

PCIe下一代线缆标准CopprLink发布

作为业界广泛采用的高速串行点对点互联标准&#xff0c;PCIe自诞生以来历经多次迭代升级&#xff0c;现已成为CPU、GPU、FPGA、SSD等计算设备间不可或缺的互连桥梁。PCIe 7.0标准更是将数据传输速率提升至令人惊叹的32 GB/s&#xff08;每通道&#xff09;。 然而&#xff0c;面…

linux上go项目打包与部署

1.第一步把项目打包 1.确保本地goland的操作系统为linux go env找到GOOS如果为window就修改为Linux 修改命令为 go env -w GOOSlinux2.打包 在项目根目录下输入 go build main.go然后项目根目录下会出现一个mian的二进制文件 3.上传包 将 main 程序包放到服务的目录下&…

俄罗斯国际消费类电子电器展ICEE:人潮如织,盛况空前

近日&#xff0c;备受全球瞩目的俄罗斯国际消费类电子电器展ICEE在莫斯科盛大落幕。本次展会为期四天&#xff0c;真的攒足了眼球&#xff0c;不仅俄罗斯这边的很多媒体和自媒体有报道&#xff0c;展会第一天&#xff0c;很多参展商通过短视频平台将展会的盛况传到了国内&#…

深入理解Python的类,实例和type函数

问题起源&#xff1a; class t():pass s1 t() s2 type("Student2",(),{}) isinstance(s1, type), isinstance(s2, type)为什么第一个是false&#xff0c;第二个是true呢 根因定位&#xff1a; 在Python中&#xff0c;一切皆对象&#xff0c;类是对象&#xff0c…

补一 继承的使用

继承的关键词为extends 模型为 public class 子类 extends 父类

C#winfrom三层架构实现简单课程管理系统管理系统,三层架构实现增删改查

1. 项目展示 1.1登录展示 1.2添加课程信息展示 1.3课程信息管理-查询-修改-删除 1.4修改登录密码 2.项目功能介绍&#xff08;图&#xff09; 3.数据库设计 3.1 教师表设计 3.2 课程分类表 3.3 课程信息表 4. 创建样式界面 winfrom 超详细UI创建过程 实现双色球选号器UI界面…

ssrf初步

一&#xff0c;简介 全称&#xff1a;Server-Side Request Forgery&#xff08;中文&#xff1a;服务器端请求伪造&#xff09; 攻击者从服务端发起请求&#xff0c;让服务器连接任意外部系统&#xff0c;从而泄露敏感数据。主要利用各种协议的请求伪造&#xff0c;例如php协…

Oracle SQL Developer导出数据库表结构,表数据,索引以及序列号等对象

目录 一、业务需求 三、环境说明 三、数据导出 四、数据导入 一、业务需求 通过Oracle SQL Developer软件将指定oralce数据库中的表结构&#xff0c;表数据&#xff0c;索引以及序列号等对象导出成SQL文件。 三、环境说明 数据库版本&#xff1a;Oracle Database 11g Expres…