架构系列——你用的线程是安全的吗?怎么解决?

简介: 架构系列——你用的线程是安全的吗?怎么解决?

前言

线程安全一般是多线程的安全,首先可以了解一些知识点:

架构系列——进程与线程的关系探索

架构系列——并发、并行与多线程关系探索

一、什么是线程安全

当多个线程访问一个类(对象或者方法),被访问者始终都能表现出正确的行为,那么这个类(对象或者方法)就是线程安全的。

二、保证线程安全的三个特性

1.原子性

提供互斥访问,同一时刻只能有一个线程对数据进行操作(atomic,synchronized);


synchronized修饰的对象有四种:


(1)修饰代码块,作用于调用的对象;


(2)修饰方法,作用于调用的对象;


(3)修饰静态方法,作用于所有对象;


(4)修饰类,作用于所有对象。

2.可见性

一个线程对主内存的修改可以及时地被其他线程看到(volatile);

3.有序性一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序(happens-before原则)。


1.程序次序规则:在一个单独的线程中,按照程序代码书写的顺序执行。


2.锁定规则:一个unlock操作happen—before后面对同一个锁的lock操作。


3.volatile变量规则:对一个volatile变量的写操作happen—before后面对该变量的读操作。


4.线程启动规则:Thread对象的start()方法happen—before此线程的每一个动作。


5.线程终止规则:线程的所有操作都happen—before对此线程的终止检测,可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。


6.线程中断规则:对线程interrupt()方法的调用happen—before发生于被中断线程的代码检测到中断时事件的发生。


7.对象终结规则:一个对象的初始化完成(构造函数执行结束)happen—before它的finalize()方法的开始。


8.传递性:如果操作A happen—before操作B,操作B happen—before操作C,那么可以得出A happen—before操作C。

三、线程安全举例

设计Thread类的子类,总共5个数,每启动一个线程,数量就减一。

package com.han;
public class MyThread extends Thread{
  private int count = 5;
  @Override
    public void run() {
        count--;
        System.out.println(this.currentThread().getName() + " count = " + count);
    }
  public static void main(String[] args) {
    MyThread myThread = new MyThread();
    Thread t1 = new Thread(myThread, "t1");
    Thread t2 = new Thread(myThread, "t2");
    Thread t3 = new Thread(myThread, "t3");
    Thread t4 = new Thread(myThread, "t4");
    Thread t5 = new Thread(myThread, "t5");
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    t5.start();
  }
}

四、出现问题

运行上面的代码出现类似下面的结果:

t1 count = 3
t3 count = 2
t2 count = 3
t4 count = 1
t5 count = 0

有两个问题:

1.剩余数量不正确,本应该是4、3、2、1、0

2.启动顺序不正确,本应该是t1、t2、t3、t4、t5

四、解决问题

1、剩余数量是由run方法里面计算的,显然有多个线程在同一时间拿到了count并进行计算。使用synchronized修饰run方法是一种比较简单的方式,还可以使用Lock,这样就能在同一时间只有一个线程拿到count


2.这个顺序不是代码的顺序,而是CPU的随机分配,可以使用队列解决


参考文献:

[1].Java中如何保证线程安全性

[2].java线程安全问题以及同步的几种方式


相关文章
|
2月前
|
人工智能 安全 Cloud Native
Nacos 3.0 架构升级,AI 时代更安全的 Registry
随着Nacos3.0的发布,定位由“更易于构建云原生应用的动态服务发现、配置管理和服务管理平台”升级至“ 一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台 ”。
|
2月前
|
存储 设计模式 人工智能
AI Agent安全架构实战:基于LangGraph的Human-in-the-Loop系统设计​
本文深入解析Human-in-the-Loop(HIL)架构在AI Agent中的核心应用,探讨其在高风险场景下的断点控制、状态恢复与安全管控机制,并结合LangGraph的创新设计与金融交易实战案例,展示如何实现效率与安全的平衡。
268 0
|
6月前
|
人工智能 运维 安全
AI 安全架构概述
AI 安全架构涵盖数据采集、模型训练、推理部署等阶段,确保安全性、隐私与合规。其核心组件包括数据层、模型层、推理层、应用层和运维层,针对数据安全威胁(如数据投毒)、模型窃取、对抗攻击及系统漏洞等风险,提出数据加密、对抗训练、联邦学习等防御策略,并强调开发前、开发中和部署后的最佳实践,以降低 AI 解决方案的安全风险。
555 13
|
5月前
|
监控 安全 数据安全/隐私保护
销售易CRM:技术架构与安全性能的深度解析
销售易CRM基于云计算与微服务架构,融合高可用性、弹性扩展及模块化开发优势,为企业提供灵活定制化的客户关系管理解决方案。系统采用多层次安全防护机制,包括数据加密、细粒度权限控制和实时监控审计,确保数据安全与隐私保护。某金融机构的成功案例表明,销售易CRM显著提升了数据安全性和系统性能,同时满足行业合规要求。作为数字化转型的利器,销售易CRM助力企业实现可持续发展与市场竞争力提升。
|
6月前
|
监控 安全 Cloud Native
企业网络架构安全持续增强框架
企业网络架构安全评估与防护体系构建需采用分层防御、动态适应、主动治理的方法。通过系统化的实施框架,涵盖分层安全架构(核心、基础、边界、终端、治理层)和动态安全能力集成(持续监控、自动化响应、自适应防护)。关键步骤包括系统性风险评估、零信任网络重构、纵深防御技术选型及云原生安全集成。最终形成韧性安全架构,实现从被动防御到主动免疫的转变,确保安全投入与业务创新的平衡。
|
6月前
|
Java 调度
Java线程池的实现架构
线程池是一种用于管理多线程的池化技术,通过复用线程减少创建和销毁线程的开销。Java中的线程池架构包括`Executor`、`ExecutorService`、`ScheduledExecutorService`等接口,以及`ThreadPoolExecutor`和`ScheduledThreadPoolExecutor`两个核心实现类。`Executors`工厂类提供了便捷的线程池创建方法。线程池不仅简化了多线程编程,还能避免线程过多导致的资源消耗和切换开销。本文从使用示例入手,剖析了线程池的实现原理及其内部架构,重点分析调度线程池的实现机制。
|
6月前
|
Java 调度
Java线程池实现架构
Java线程池实现架构
|
9月前
|
缓存 安全 Java
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
|
9月前
|
Java 调度
【JavaEE】——线程的安全问题和解决方式
【JavaEE】——线程的安全问题和解决方式。为什么多线程运行会有安全问题,解决线程安全问题的思路,synchronized关键字的运用,加锁机制,“锁竞争”,几个变式

热门文章

最新文章