03 线程安全问题
一、什么时候会出现线程安全问题?
无线程安全问题:
1、在单线程中不会出现线程安全问题
2、java领域的线程安全问题,通常是全局变量或静态变量引起的,若每个线程对共享变量只有读操作,一般来说该变量是线程安全的,若有写操作,则需要考虑线程安全问题。
3、当多个线程执行一个方法,方法内部的局部变量并不是临界资源,因为方法是在栈上执行的,而Java栈是线程私有的,因此不会产生线程安全问题。
线程安全问题:
1、有多个线程时,同时访问同一个资源(一个对象,对象中的属性,一个文件,一个数据库等),会导致程序运行结果并不是想要的。
举个简单的例子:
现在有两个线程分别从网络上读取数据,然后插入一张数据库表中,要求不能插入重复的数据。那么必然在插入数据的过程中存在两个操作:
1)检查数据库中是否存在该条数据;
2)如果存在,则不插入;如果不存在,则插入到数据库中。
假如两个线程分别用thread-1和thread-2表示,某一时刻,thread-1和thread-2都读取到了数据X,那么可能会发生这种情况:
thread-1去检查数据库中是否存在数据X,然后thread-2也接着去检查数据库中是否存在数据X,结果两个线程检查的结果都是数据库中不存在数据X,那么两个线程都分别将数据X插入数据库表当中。
这里面,这个资源被称为:临界资源(也有称为共享资源)。
二、如何解决线程安全问题?
通常是在访问临界资源的代码前面加锁,当访问完临界资源后释放锁,让其他线程继续访问。
2.1 单机
单机多线程情况,可以通过 synchronized 或者 Lock 进行加锁,是Java中提供的两种方式来实现同步互斥访问。
2.2 分布式系统
现在大部分应用都是采用分布式的方式进行部署,属于多进程的情况,这可以通过分布式锁、原子操作来解决。a. 分布式锁的实现方式有
- 基于数据库的分布式锁 分布式锁三种实现方式及对比
- 基于缓存(Redis)的分布式锁
- 基于 Zookeeper 的分布式锁
- 单命令:把多个操作在Redis中实现成一个操作,也就是单命令操作。Redis是使用单线程来串行处理客户端的请求操作命令的,所以,当Redis执行某个命令操作时,其他命令是无法执行的,这相当于命令操作是互斥执行的。
- Lua脚本:把多个操作写到一个Lua脚本中,以原子性方式执行单个Lua脚本。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话