线程安全的三大特性(原子性、可见性、有序性)

本文详细阐述了线程安全的三大核心特性:原子性、可见性和有序性,并通过具体场景说明了违背这些特性可能引发的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程安全的三大特性


0、如何保证线程安全
①原子性
指定代码块是原子操作。
②可见性
修改共享变量时,立即同步到主存中,并使该修改对其他线程可见
③有序性
禁止读取共享变量后的代码、修改共享变量前的代码重排序。



1、违背原子性、可见性、有序性可能出现的问题
问题一:违背原子性
场景:
线程一和线程二同时对共享变量执行修改操作;( i++ 为例)。
i++ 可以拆分为:读取 i 的值、读取的值加1、修改 i 的值。


细节:
首先默认 i 等于 0,线程一二同时执行 i++ ,线程一先获得时间片,线程二等待。
线程一______________________________线程二
读取 i , 值为0_________________________等待
值(0)加1为1________________________等待
时间片用完,执行线程二________________读取 i , 值为0 (此时线程一还没有修改 i )
等待________________________________值(0)加1为1
等待________________________________修改 i 的值 ,此时 i = 1;
修改 i 的值 ,此时 i = 1_________________时间片用完,执行线程一
最后经过两次 i++ 操作, i 的值为1 。



问题二:违背可见性
依然使用 i++ 场景


细节:
首先默认 i 等于 0,线程一二同时执行 i++ ,线程一先获得时间片,线程二等待。
线程一______________________________线程二
读取 i , 值为0_________________________等待
值(0)加1为1________________________等待
修改 i 的值 ,此时 i = 1_________________等待
时间片用完,执行线程二________________读取 i , 值为0(虽然此时线程一已经修改 i 的值为1,但还没有同步到主存中 )
等待________________________________值(0)加1为1
等待________________________________修改 i 的值 ,此时 i = 1;
最后经过两次 i++ 操作, i 的值为1 。



问题三:违背有序性
场景:
执行以下代码

共享变量
boolean canStart = false;
ClassPathXmlApplicationContenxt context = null;

线程一执行
void permitStart(){
    context = new ClassPathXmlApplicationContenxt("spring.xml");
    canStart = true;
}

线程二执行
void start(){
    if(canStart){
        context.start();
    }
}


细节:
首先默认 canStart 为 false, context 为空 , 线程一执行permitStart方法,线程二执行start()方法,线程一先获得时间片,线程二等待。
线程一______________________________线程二
发生重排序,先执行canStart = true;_______等待
时间片用完,执行线程二________________if(canStart)通过
等待________________________________contenxt.start()抛出NullPointException。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值