文章目录
并发编程三大特性:
- 可见性
- 有序性
- 原子性
1. 什么是进程?什么是线程?
进程:资源分配(静态)
线程:任务调度(动态)
2. 线程切换

Contact Switch
CPU 执行 T1 时,把 T1 的指令和数据放到CPU里,如果需要切换线程了,就把 T1 存在寄存器里的数据和PC 里面的地址 放到 cache 里面,然后就把 T2 的指令和数据放进来;
3. 四核八线程是什么意思

CPU里面有ALU 和 Registers ,ALU负责运算,Registers存取数据;
一个 ALU相当于一个核;一组寄存器可以存放一个线程的数据;所以,当一个ALU 能够对应两组寄存器,那么就是四核八线程!超线程亦是如此;
3.1 单核CPU设定多线程是否有意义
单核CPU设定多线程,当一个线程等待资源分配或者别的事件发生时,CPU可以运行别的线程,提高效率;这和分时操作系统并发运行多个进程的本质一样;
4. 并发编程的原子性
原子性:一个操作或多个操作要么全部执行完成且执行过程不被中断,要么就不执行;
比如 i=1 是原子操作,只涉及赋值;而 i++ 就不是原子操作,它相当于语句i=i+1;这里包括读取i,i+1,结果写入内存三个操作单元;
并发编程中,因此如果操作不符合原子性操作,那么整个语句的执行就会出现混乱,导致出现错误的结果,从而导致线程安全问题;
4.1 如何解决原子性问题 & atomic(底层CAS)
如何保证操作的原子性呢?
- 加锁,这可以保证线程的原子性,比如使用 synchronized 代码块保证线程的同步,从而保证多线程的原子性。但是加锁的话,就会使开销比较大;
- 使用J.U.C下的 atomic 来实现原子操作;
atomic 的底层是CAS(compareAndSwap),是一条 CPU 并发原语;CAS 并不是一种实际的锁,它仅仅是实现乐观锁的一种思想,java 中的乐观锁(如自旋锁)基本都是通过 CAS 操作实现的,CAS 是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。
CAS 算法,即 compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。 CAS 算法涉及到三个操作数:
- 需要读写的内存值 V
- 预期原值 A
- 拟写入的新值 B
如果内存位置的值V与预期原值A相匹配,那么处理器会自动将该位置值V更新为新值B。否则,处理器不做任何操作。无论哪种情况,它都会返回该位置的【值】;(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS 有效地说明了"我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。"

基于 CAS 的并发算法称为无阻塞算法,因为线程不必再等待阻塞。无论 CAS 操作成功还是失败,在任何一种情况中,它都在可预知的时间内完成。如果 CAS 失败,调用者不会被挂起而是可以重试(轮询) CAS 操作或采取其他适合的操作。
CAS 优点:
- synchronized涉及线程之间的切换,存在用户状态和内核状态的切换,耗费巨大。CAS只是CPU的一条原语,是一个原子操作,消耗较少;
缺点:
- ABA 问题;
因为 CAS 需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是 A ,变成了 B ,又变成了 A ,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么 A-B-A 就会变成 1A - 2B-3A。从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference 来解决 ABA 问题。这个类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
AtomicStampedReference相关方法:
// 比较设置 参数依次为:期望值 写入新值 期望版本戳 新版本戳
public

本文探讨了进程与线程的区别,线程切换机制,四核八线程的含义,以及单核多线程的意义。重点讲解了并发编程中的原子性、可见性和有序性,包括CAS原理、volatile的作用、内存屏障和指令重排。此外,还涉及了单例模式中volatile的应用和为何JMM需要volatile。
最低0.47元/天 解锁文章
1830

被折叠的 条评论
为什么被折叠?



