File tree Expand file tree Collapse file tree 1 file changed +30
-0
lines changed
languages/java/mutil-thread Expand file tree Collapse file tree 1 file changed +30
-0
lines changed Original file line number Diff line number Diff line change @@ -205,6 +205,36 @@ public class Singleton {
205205volatile的三重功效:64位写⼊的原⼦性、内存可⻅性和禁⽌重排序。
206206volatile 关键字只保证了对变量的读写操作的可见性和顺序性,并不保证原子性。如果需要保证原子性,可以考虑使用其他同步机制,如锁或原子类
207207
208+ 二、CAS
209+ CAS存在三大问题:ABA问题,循环时间长且开销大,以及只能保证一个共享变量的原子操作;
210+ ABA问题的场景如下:
211+
212+ 1.初始状态,共享变量的值为A。
213+ 2.线程1读取共享变量的值A。
214+ 3.在线程1读取值A的同时,线程2将共享变量的值从A修改为B,然后又修改回A。
215+ 4.线程1执行CAS操作,比较共享变量的值为A,发现与预期值相等,于是进行更新操作。
216+ 在这种情况下,CAS操作成功,因为线程1读取共享变量时,发现其值与预期值相等。然而,实际上共享变量的值已经发生了变化,虽然在值的变化过程中经历了A->B->A的变化,但是线程1并不知道这个过程,它仅仅是关注共享变量的当前值与预期值是否相等。
217+
218+ 这就是ABA问题,CAS操作成功,但忽略了共享变量的值在过程中发生了其他变化。ABA问题可能导致一些潜在的风险和错误,特别是在并发数据结构和多线程算法中使用CAS时。
219+
220+ 为了解决ABA问题,可以使用版本号或标记来跟踪共享变量的变化。每次共享变量发生变化时,版本号或标记也会相应地增加。这样,在CAS操作时,不仅要比较值是否相等,还要比较版本号或标记是否匹配。如果版本号或标记不匹配,说明共享变量在过程中发生了变化,CAS操作将失败。
221+
222+ ** 如果修改失败如何解决** :
223+ 1.自旋重试:在获取失败后,可以使用自旋重试的方式,即反复尝试执行CAS操作,直到获取成功或达到一定的尝试次数或时间限制。自旋重试避免了线程的上下文切换,适用于短时间内锁竞争不激烈的情况。
224+ 2.适当延迟:为了减少不必要的CPU自旋消耗,在获取失败后可以适当地引入延迟。可以使用Thread.sleep()等方法在重试之前让线程进行短暂的休眠,以降低CPU占用。
225+ 3.加锁:如果CAS操作失败的次数较多或存在激烈的竞争情况,可以考虑使用传统的加锁机制,如使用synchronized关键字或ReentrantLock,来保证线程的互斥访问。加锁可以避免无限自旋的情况,但也会引入线程的上下文切换和额外的开销。
226+ 4.采用其他策略:根据具体的业务场景和需求,还可以采用其他策略来处理CAS获取失败的情况。例如,可以选择放弃当前操作、回退到其他实现方式,或者根据具体情况进行异常处理等。
227+
228+ 二、为什么频繁创建线程会需要时间,具体那部分的时间
229+
230+ 线程分为守护线程和非守护线程
231+ 当Java程序的所有非守护线程都执行完毕时,程序会正常退出,无论是否还存在守护线程。非守护线程是程序的主要执行线程,它们执行程序的核心逻辑。一旦所有非守护线程执行完毕,JVM会自动退出,无需显式地停止守护线程。
232+
233+ 然而,如果还存在活跃的非守护线程,程序仍然可以继续执行。在这种情况下,守护线程的行为会有所影响。
234+
235+ 守护线程是一类特殊的线程,它的生命周期与非守护线程不同。当程序中只剩下守护线程时,JVM会判断程序已经不再需要继续执行,因此会强制终止所有守护线程,然后退出程序。
236+
237+
208238[ 面试官:Java线程与底层操作系统线程是一 一对应的吗? 中篇[ 一] _ mob60475706bec5的技术博客_51CTO博客] ( https://blog.51cto.com/u_15127698/2842977 )
209239
210240## 1.什么是线程?
You can’t perform that action at this time.
0 commit comments