线程安全 如何实现线程安全
2022/1/28 23:04:29
本文主要是介绍线程安全 如何实现线程安全,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
什么是线程安全
多线程执行某段代码,不对这段代码进行同步处理、线程间的协调,程序运行的结果仍与预期一致,这就是线程安全。
多线程编程的三个核心概念
原子性
: 同数据库事务的原子性,一些操作要么全部成功,要么全部失败,经典的例子就是银行转账。可见性
:多线程并发访问共享变量时,某个线程对共享变量的更新,其他线程能立即看到这个更新。
现代的计算机都有几层缓存,一个变量在多个线程中共享,每个线程都会对这个变量进行缓存,某个线程内部更新该变量会立即更新缓存,但不会立即更新主内存,这使得其他线程无法立即观察到这个更新变化。
顺序性
: 指程序顺序执行代码中的操作。
编译器、处理器会对代码的执行顺序进行优化,以提高处理速度。因此程序实际的执行顺序可能与代码中的不一样,但编译器、处理器保证结果是一样的。
如何保证原子性
使用synchronized、ReentrantLock作用于一段代码,同一时刻只能有一个线程能进入这段代码,保证了原子性、可见性、顺序性。使用synchronized、ReentrantLock的性能较差,因为一个线程占有锁,其他线程会阻塞,线程的挂起和唤醒会降低处理速度。
使用AtmoicInteger、AtmoicLong、AtmoicReference,底层使用CAS(compare and swap)。
如何保证可见性
使用synchronized、ReentrantLock作用于一段代码,同一时刻只能有一个线程能进入这段代码,保证了原子性、可见性、顺序性。使用synchronized、ReentrantLock的性能较差,因为一个线程占有锁,其他线程会阻塞,线程的挂起和唤醒会降低处理速度。
java使用volatile关键字来保证可见性。被volatile修饰的变量,当被某个线程更新时,会立即更新主内存,并将该变量的所有缓存设置为无效。其他线程想要获取该变量必须访问主内存。
如何保证顺序性
编译器、处理器会对代码的执行顺序进行优化,以提高处理速度。因此程序实际的执行顺序可能与代码中的不一样,但编译器、处理器保证结果是一样的。在单线程程序下结果是正确的,但在多线程下有可能不正确。
使用volatile可以一定程度上保证顺序性。
使用synchronized、ReentrantLock作用于一段代码,同一时刻只能有一个线程能进入这段代码,保证了原子性、可见性、顺序性。使用synchronized、ReentrantLock的性能较差,因为一个线程占有锁,其他线程会阻塞,线程的挂起和唤醒会降低处理速度。
如何实现线程安全
互斥同步
: 使用synchronized、ReentrantLock作用于一段代码,同一时刻只能有一个线程能进入这段代码,保证了原子性、可见性、顺序性。非阻塞同步
: CAS(compare and swap)是非阻塞同步的计算机指令, 它有三个操作数,内存位置、旧的预期值、新值,当内存位置的值与旧的预期值相等时才将新值存入内存位置。对于ABA问题,可使用AtomicStampedReference,通过引入版本号解决。无同步
: 使用ThreadLocal将共享变量的可见性限制在线程内部,每个线程维护一个共享变量的副本,线程间相互隔离,不再争用数据。
这篇关于线程安全 如何实现线程安全的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-15JavaMailSender是什么,怎么使用?-icode9专业技术文章分享
- 2024-11-15JWT 用户校验学习:从入门到实践
- 2024-11-15Nest学习:新手入门全面指南
- 2024-11-15RestfulAPI学习:新手入门指南
- 2024-11-15Server Component学习:入门教程与实践指南
- 2024-11-15动态路由入门:新手必读指南
- 2024-11-15JWT 用户校验入门:轻松掌握JWT认证基础
- 2024-11-15Nest后端开发入门指南
- 2024-11-15Nest后端开发入门教程
- 2024-11-15RestfulAPI入门:新手快速上手指南