Java 并发
并发问题的核心 在并发编程领域要解决的三个核心问题: 分工,同步,互斥 分工: 将任务分解,进行执行典型的有生产者-消费者模型 同步:分工好之后任务之间需要协作,需要通信,线程的执行顺序等问题都要解决 互斥:同一时刻只允许一个线程访问共享资源,否则将引起混乱。锁的实现保证等 并发问题源头 1. 可见性 随着多核 CPU 的发展,缓存机制的引入,这就导致了主存中的变量或者数据同时存在于多个 CPU 的缓存中,这就导致了多个线程间数据的可见性问题。 2.原子性 CPU 在进行线程切换的时候采用时间片轮换方式,当一个线程A 的时间片用完但是线程任务未执行完,CPU 使用权被交给另外一个线程 B,此时 B按照相同的代码逻辑从 内存加载数据,执行操作,写回内存执行完毕。此时 A 又回来开始执行未执行完的操作,这时 A 所操作的那份数据的拷贝对内存数据来说已经为老版本了,在此数据上继续操作将覆盖掉 B 所做的更新,导致不期望的执行结果。上述的操作就破坏了原子性,当一个或多个操作在 CPU 执行过程中不被中断的特性称为原子性。 3.有序性 有序性问题常源自编译器优化带来的指令重...
Read post
Java 创建对象
1.创建对象 1.去常量池中找对于类的符号引用--->检查类是否被加载,解析,初始化过 2.进行类加载 3.加载完之后进行对象堆内存分配(大小在类加载完之后就已知),分配根据内存是否规整,分为指针碰撞(就是一个分界线)和空闲列表,规整由 GC 收集器是否压缩决定,Serial,ParNew 是指针碰撞,CMS 为空闲列表 4.处理对象分配时多线程的对象指针,CAS + 重试还有 TLAB (本地线程分配缓冲)保证每个线程在自己的 TLAB 分配对象 5.对对象分配的区域进行初始化零值,一些默认类型的值 6.设置对象头,包含类的 metadata,对象 GC 分代年龄等 7.执行对象的 init 方法 2.对象内存布局 包含三部分: 对象头,对象实例数据,对齐填充 2.1 对象头 第一部分:运行时数据 内容 状态 对象哈希,分代年龄 未锁定 指向锁记录的指针 轻量级锁定 指向重量锁指针 锁膨胀(重量锁锁定) 空 GC 标记 偏向线程 ID,时间戳,对象分代年龄 可偏向锁 第二部分:类型指针 对象指向类 metadata 的指针...
Read post
CPU Cache 与 MESI
CPU 缓存 由于CPU 在计算之前存在取指-->译码-->执行 三个阶段,在计算之前需要将前两步准备好,并且准备好操作数,这样才能够最大效率的利用 CPU,但是CPU 的存储读写速度与主存存在巨大的差距,则引入 cache 来消减这个差距,cache 使用的是 SRAM ,SRAM 是 Static Random Access Memory 静态RAM 集成度高速度快,,他比我们的 主存(DRAM)速度快所以用其来做 CPU L1 L2 L3(速度依次降低) 等缓存 Cache 一致性问题 主存中的内存块是按照缓存行映射加载到 cache 中的,缓存行由 如下接口组成 状态 地址 数据 对于多核 CPU 来说每个核都有自己对应的 L1,L2 缓存,L3共享缓缓存,那同一块内存快就有可能被多个CPU 加载到自己的缓存中进行数据的操作,那就会带来缓存一致性问题,如何保证数据内存快的数据一致是需要解决的问题 MESI 协议缓存一致性解决方案 CPU 修改 cache 中的数据后对数据的处理: wirte through :每次修改之后立即更新到主存,...
Read post