【Java第74集】java线程安全的概念详解

文章目录

  • 一、多线程概念
    • 1. 同步与异步
      • 同步(Synchronous)
      • 异步(Asynchronous)
    • 2. 阻塞与非阻塞
      • 阻塞(Blocking)
      • 非阻塞(Non-blocking)
    • 3. 并发与并行
      • 并发(Concurrency)
      • 并行(Parallelism)
  • 二、什么是线程安全?
  • 二、实现线程安全的方式
    • 1、避免数据共享
      • (1)无状态代码
      • (2)不可变对象
      • (3)使用volatile修饰
      • (4)线程封闭
      • (5)数据隔离设计
    • 2、数据必须共享
      • (1)互斥同步(阻塞同步)
      • (2)非阻塞同步

一、多线程概念

1. 同步与异步

同步(Synchronous)

  • 定义:任务按照顺序依次执行,每个任务必须等待前一个任务完成后才能开始。
  • 特点
    • 阻塞:当前任务未完成时,后续任务必须等待。
    • 线性执行:程序流程是线性的、可预测的。
    • 简单易懂:逻辑清晰,适合调试。
  • 缺点
    • 性能低:耗时任务会阻塞后续任务,导致资源浪费。
    • 无法利用并发:无法充分利用多核CPU或多线程的优势。

异步(Asynchronous)

  • 定义:任务可以并发执行,无需等待前一个任务完成。
  • 特点
    • 非阻塞:任务发起后立即返回,后续代码继续执行。
    • 并发执行:多个任务同时进行,提升效率。
    • 复杂性高:需要处理回调、事件或状态通知。
  • 优点
    • 高性能:适合I/O密集型或耗时任务。
    • 响应快:避免主线程阻塞,提升用户体验。
  • 缺点
    • 逻辑复杂:可能引发竞态条件、数据不一致等问题。
    • 调试困难:依赖回调或事件驱动,控制流不直观。

2. 阻塞与非阻塞

阻塞(Blocking)

  • 定义:当程序发起一个操作(如读取数据)时,如果资源未就绪或操作未完成,当前线程会暂停执行,等待直到操作完成或资源可用。
  • 特点
    • 线程进入等待状态(挂起),无法执行其他任务。
    • 操作完成后自动恢复线程执行。
    • 实现简单,但可能导致资源浪费(如CPU空转)。

非阻塞(Non-blocking)

  • 定义:当程序发起一个操作时,如果资源未就绪或操作未完成,函数会立即返回,不会阻塞线程,而是返回一个状态码(如错误码或“未就绪”提示)。
  • 特点
    • 线程继续执行后续代码,无需等待操作完成。
    • 需要轮询(Polling)或事件驱动(Event-driven)机制检查操作是否完成。
    • 提高资源利用率,但实现复杂度较高。

3. 并发与并行

并发(Concurrency)

  • 定义:多个任务在同一时间段内交替执行,宏观上表现为“同时进行”,但微观上是通过快速切换时间片实现的。
  • 特点
    • 不依赖多核CPU,单核即可实现。
    • 通过时间片轮转事件驱动模拟“同时执行”。
    • 关注任务的调度与管理,而非物理上的同时执行。
  • 示例
    单核CPU运行一个多线程程序,线程A执行10ms → 切换到线程B执行10ms → 再切换回线程A,用户感知为“同时运行”。

并行(Parallelism)

  • 定义:多个任务真正同时执行,需要硬件支持(如多核CPU、分布式系统)。
  • 特点
    • 依赖多核CPU或多台计算机。
    • 任务在物理上同时执行,无需切换上下文。
    • 关注任务的分解与分配,以最大化计算效率。
  • 示例
    8核CPU运行一个视频渲染程序,每个核心独立处理一帧,8个帧同时渲染。

二、什么是线程安全?

  • 什么是线程安全?下面是我摘自java并发编程书里给的解释:

    当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。

  • 这个解释听的是不是云里雾里?我们说的通俗一点:

    线程安全就是多线程并发访问的时候,确保共享资源的访问顺序和结果都符合预期。

  • 线程安全需保证以下几点:

    • 原子性(Atomicity):操作不可分割,要么全部完成,要么全部不执行。
    • 可见性(Visibility):一个线程修改共享变量后,其他线程能立即看到最新值。
    • 有序性(Ordering):代码执行顺序符合预期,避免指令重排序导致的逻辑错误。
  • 线程不安全的典型表现:

    • 数据竞争(Data Race):多线程同时修改共享变量导致结果不可预测。
    • 脏读(Dirty Read):读取到其他线程未完成的中间状态数据。
    • 死锁(Deadlock):多个线程互相等待对方释放锁,导致永久阻塞。

我们知道线程共享的内存区域主要就是java堆,而java堆主要存的就是对象和数组,所有的全局变量都存储在堆中。也就是说我们想保证线程安全,就需要保证全局变量和堆内的对象不会受其他线程影响。-------->JVM内存模型介绍传送门


二、实现线程安全的方式

我们可以从数据共享和不共享两个方面来讨论实现线程安全的方式:

1、避免数据共享

通过避免数据共享,让所有资源都变成线程私有,达到线程安全。主要实现方法有以下几种:

(1)无状态代码

当多个线程访问公共资源的时候,才可能出现数据安全问题,那么如果我们的整个类的代码没有使用公共资源,那么这个类就是线程安全的。

(2)不可变对象

当多个线程访问的对象是不可变或者对象的属性都不可变,那么这个类就是线程安全的。

  • 通过使用final修饰类,发布不可变对象。String属于不可变对象,可直接使用。
  • 通过使用private final修饰属性,确保对象的属性不可修改。
  • 通过不提供对象的内部修改方法,确保对象不被修改。

(3)使用volatile修饰

通过使用Volatile类型修饰,保证所有线程读到的都是最新的状态。volatile类型修饰的变量只适用于一写多读情况,只能确保其可见性,如果要保证线程安全,则需要保证只有单个线程去修改。

(4)线程封闭

通过确保资源属于线程私有,使用线程的本地存储,即使用ThreadLocal类存储对象。

  • ThreadLocal提供类get()和set()等方法,为每个使用该变量的线程都保存一份独立的副本。Thread类中有一个成员变量ThreadLocal.ThreadLocalMap,ThreadLocalMap则定义在ThreadLocal类中的静态内部类,它是一个Map,他的key是线程对象,value是线程的变量副本。

(5)数据隔离设计

通过程序设计上控制数据访问在单一线程内串行执行,比如根据用户ID设计不同的数据结构,保证线程在该用户下不会受其他用户干扰,达到与其他用户的数据完全隔离的效果。


2、数据必须共享

保证数据共享安全,即保证数据同步。同步的方式主要有以下:

(1)互斥同步(阻塞同步)

为了保证多线程在同一时间访问共享数据的安全性,我们可以通过加互斥锁使共享数据每次只被一个线程访问,这样就能保证线程安全,但是同时线程会被阻塞。互斥同步的主要实现方式是加锁,主要有以下方式:

  • synchronized关键字:java内置锁,可重入。同步代码块的锁就是方法调用所在的对象,静态的synchronized方法以Class对象作为锁。进入占有锁,退出释放锁(无论是正常还是异常退出)。

  • Lock接口:实现Lock接口,它包含了: 公平锁 、 非公平锁 、可重入锁 、 读写锁等更多更强大的功能。默认的是非公平锁 false,必须手动释放锁。常见的实现类有ReentrantLock和ReentrantReadWriteLock。相较于synchronized优势:

      1. 可实现公平锁 (构造参数传true)
      1. 可响应中断
      1. 获取锁限时等待
      1. 结合Condition实现等待通知机制
  • 分布式锁:如果是在单机的情况下,使用synchronized和Lock保证线程安全是没有问题的。但如果在分布式集群环境中,即某个应用如果部署了多个集群下的多个节点,每一个节点使用可以synchronized和Lock保证线程安全,但不同的节点之间,没法保证线程安全。此时就需要考虑使用分布式锁了。分布式锁有很多种,比如:数据库分布式锁,zookeeper分布式锁,redis分布式锁等。

(2)非阻塞同步

  • CAS(Compare And Swap)锁机制
    • 使用 Atomic 类 (原子变量),Java 提供了 java.util.concurrent.atomic包中的一组类,如AtomicInteger、AtomicLong、AtomicReference 等,它们通过 CAS(Compare And Swap)机制提供了线程安全的操作。
  • JUC线程安全类:Java提供的并发包中的高效线程安全集合(java.util.concurrent),比如ConcurrentHashMap、CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentLinkedQueue等。

你可能感兴趣的:(Java基础,java,开发语言)