线程安全问题 --- 死锁

本文探讨了线程安全问题的原因,包括多线程抢占式执行、非原子操作等因素,并介绍了Java中`synchronized`关键字的用法,如修饰方法和代码块。文章深入讲解了死锁的概念、必要条件及避免死锁的方法,还提到了Java中的线程安全类,如`Collections.synchronizedXXX`系列方法。
摘要由CSDN通过智能技术生成

线程安全

由于多个线程之间是抢占式执行的, 这就给调度执行顺序带来了随机性, 程序员需要在n多个调度执行顺序中保证每一个顺序最后执行的结果都是正确的, 如果其中有一个执行顺序出错, 则视为是出现bug, 即发生了线程安全问题
下面是一个有线程安全问题的代码:

package Thread;
class Add{
   
    int a = 0;
    public void add(){
   
        for(int i = 0 ; i < 50000; i++){
   
            a++;
        }
    }
}
public class ThreadDome11 {
   
    public static void main(String[] args) {
   
        Add a = new Add();
        Thread t1 = new Thread(()->{
   
            a.add();
        });
        Thread t2 = new Thread(()->{
   
            a.add();
        });
        t1.start();
        t2.start();
        try {
   
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
   
            throw new RuntimeException(e);
        }
        System.out.println("最终值为:" + a.a);
    }
}

在这里插入图片描述两个线程各自给a自增五万次, 最后的结果有可能小于, 等于五万, 也有可能大于五万, 等于十万等诸多结果

产生线程安全问题的原因

  1. 多线程之间抢占式执行, 随机调度(根本原因)
  2. 多个线程对同一变量进行修改操作
  3. 非原子操作(一行代码会被编译成多条机器指令), 只有非原子操作才会产生线程安全问题
  4. 内存可见性
  5. 指令重排序, 编译器在进行代码优化时, 可能会调整代码顺序

针对以上原因中, 非原子操作的解决方法最实用, 解决方法是将非原子操作原子化, 具体方法是通过上锁
通过上锁可解决第二和第三个原因引起的线程安全问题, 而第四和第五需要用volatile关键字来解决, 这个下篇文章介绍, 本篇主要介绍上锁

上锁

java中上锁的关键字为synchronized, 如果一个线程已经被加锁, 另一个线程也要加锁, 那么其就会陷入阻塞(CLOCKED)状态, 等待第一个线程被解锁之后再进行加锁操作, 此期间即使线程1不在cpu上执行, 线程2也不能被调度
将上诉代码进行如下修改:

class Add
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

With Order @!147

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值