来讲讲多线程问题以及解决方法

引言

        一个变量是count=0,如果A、B线程同时对count++一百万次,最后count的结果会是两百万吗?

一、为什么不是两百万

1.原子性

        既然提出这个问题,那么答案就不会是简单的两百万,因为在整个过程中count是共享的变量,会出现数据覆盖问题,数据覆盖是多线程并发编程中最经典的竞态条件问题,根本原因是count++不是原子操作

        count++看似是一行代码,但是底层分为三步:这三步不是原子的

  • :从内存拿到 count 当前的值
  • :把值 +1
  • :把新值存回内存

        原子是什么?大家高中物理应该都学过原子吧,在这里就是一个不可分割、不可打断的操纵

2.覆盖数据

举个最简单的例子:count 初始 = 0

  • 线程 A 读到 0
  • 线程 B 也读到 0
  • 线程 A 算成 1,写回去 → count=1
  • 线程 B 也算成 1,写回去 → count=1

两个线程都执行了 ++,结果却只加了 1!

这就叫:线程安全问题 → 竞态条件 → 数据覆盖

3.总结

        count++ 不是原子操作,多线程同时执行时,步骤会互相穿插,导致结果错误。

二、多线程

        理解多线程,可以从下面几方面来认识

1. 共享资源

        多个线程能同时访问的变量 / 对象,就是共享资源。比如:countlistmap对象属性

只要多线程改共享资源,就可能线程不安全。

2. 原子性(最重要!)

原子操作 = 不可分割、不可打断的操作

例子:

  • x = 1 → 原子
  • x++非原子(三步)
  • x = y非原子

非原子操作在多线程下一定不安全!

3. 可见性

一个线程改了变量,另一个线程能不能立刻看到

CPU 有缓存,线程会把变量读到自己的缓存里。如果不刷新回主内存,别的线程看不到最新值。

4. 有序性

代码执行顺序会不会被打乱?JVM 和 CPU 会优化重排指令,单线程没事,多线程会出问题。

5.总结

要保证线程安全,必须同时满足:

  1. 原子性(操作不被打断)
  2. 可见性(修改立刻能看到)
  3. 有序性(指令不胡乱重排)

三、解决方案---synchronized

   synchronized 是 Java 内置的锁,用来解决线程不安全。它能同时保证原子性、可见性、有序性

1.概念

        这个到底是什么?用一句话来说:加锁 → 同一时间只有一个线程能执行这段代码

就像厕所:

  • 一个人进去 → 锁门
  • 其他人必须排队等
  • 出来 → 解锁,下一个人进

2.它是如何解决多线程问题的

        对共享变量进行加锁,那么就会变成原子操作:

synchronized(锁对象) {
    count++; // 这一段变成原子操作!
}

        实现效果:不会发生文章开头说的数据覆盖问题,结果一定正确

  • 线程 A 进来,上锁
  • 其他线程全部阻塞等待
  • A 执行完 读 + 改 + 写
  • 解锁
  • 下一个线程才能进

3.synchronized 的 3 种用法

用法一:同步代码块(最常用、最推荐)

        锁粒度最小,性能最好

private Object lock = new Object();

public void add() {
    synchronized (lock) {  // 锁这个对象
        count++;
    }
}

用法二:修饰实例方法

        锁的是当前对象this

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

用法三:修饰静态方法

        所的是类对象(全局唯一)

public static synchronized void add() {
    count++;
}

4.synchronized保证了什么(核心)

  1. 原子性:同一时间只有一个线程执行
  2. 可见性:解锁前会把数据刷回主内存
  3. 有序性:加锁解锁前后不会指令重排

它是并发的 “全能解决方案”

5.底层原理(简单理解)

  • 每个对象都有一个 监视器锁 (monitor)
  • 加锁就是获取 monitor
  • 解锁就是释放 monitor
  • JVM 自动管理,不用手动关锁

四、总结

  • count++ 是非原子操作,多线程会算错
  • 线程不安全根源:共享资源 + 非原子操作 + 多线程修改
  • 并发三大特性:原子性、可见性、有序性
  • synchronized 加锁 → 同一时间只有一个线程执行
  • synchronized 能同时保证三大特性,彻底解决线程安全
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值