那些年读过的书《Java并发编程的艺术》一、并发编程的挑战和并发机制的底层实现原理

时间:2021-05-16 18:36:00

一、并发编程的挑战

1、上下文切换

(1)上下文切换的问题

      在处理器上提供了强大的并行性就使得程序的并发成为了可能。处理器通过给不同的线程分配不同的时间片以实现线程执行的自动调度和切换,实现了程序并行的假象。

      在单线程中:线程保存串行的执行,线程间的上下文切换不会造成很大的性能开销。

      而在多线程中:线程之间频繁的调度需要进行上下文切换以保存当前执行线程的上下文信息和加载将要执行线程的上下文信息,而上下文切换时需要底层处理器、操作系统、Java虚拟机提供支持的会消耗很多的性能开

销。如果频繁的进行上下文切换势必影响程序执行的速度。

(2)如何查看上下文切换的开销

     1)使用性能分析工具Lmbench3测量上下文切换的时长

     2)使用vmstat测量上下文切换的次数

     3)使用jstack命令查看线程的dump信息

(3)如何减少上下文切换

       1)无锁并发编程:多线程竞争锁时会引起上下文切换,使用无锁编程通过避免使用锁来减少上下文切换

       2)CAS算法:使用Java内Automic的原子类的CAS操作

       3)减少线程数量:线程越少,上下文切换的次数就越少

       4)单线程:在单线程内实现任务的调度和执行

2、死锁

(1)如何避免死锁

 

3、资源限制的挑战

(1)硬件资源的限制和处理办法

硬件资源限制有带宽的上传下载速度、硬盘的读写速度、CPU的处理速度

处理办法:集群化

(2)软件资源的限制和处理办法

软件资源限制有数据库的连接数,socket的连接数.

处理办法:共享软件资源即软件资源的复用

 

二、并发机制的底层实现原理

1、volatile与synchronized实现原理和区别

1)volatile和synchronized的区别

关键字

功能特性

实现原理

优点

缺点

适用范围

说明

volatile 1、实现变量的内存可见性
2、禁止指令的重排序
3、JVM内置的属性
内存屏障指令防止重排序和缓存一致性嗅探技术实现内存可见性 1、确保内存的可见性
2、不会引起线程上下文切换和调度
1、仅仅保证单个volatile变量的读写操作的原子性,不能保证复合操作的原子性 1、只有单个线程更新变量的值
2、该变量不会与其他变量存在依赖(也就是不一起构成实例对象的不变性)
3、访问变量的时候不需要加锁
三个条件同时满足的时候才可使用。
1、volatile写操作的开销比volatile读操作多。
synchronized 1、实现内存的可见性
2、确保操作的互斥性和原子性
3、禁止指令的重排序
4、JVM内置的属性
加锁机制 1、确保内存的可见性
2、确保所包含区域操作的原子性
1、在严重的线程竞争的时候性能开销大
2、加锁机制会引起线程上下文切换和调度
任何需要同步机制的地方都可以使用 1、synchronize的读写操作开销一样

2)内存屏障:限制内存操作顺序的指令

      内存屏障指令LOCK:禁止重排序,使用缓存锁定或者主内存锁定来确保处理器缓存(线程的工作内存)的数据会写到主内存当中。

应用:

          volatile变量写的时候,编译器会在该代码编译后的指令后面加上一条LOCK指令,以禁止重排序

3)嗅探技术:实现缓冲一致性协议

      基于缓存的一致性协议,嗅探技术确保各个处理器的缓存和主内存之间数据保存一致。各个处理器通过嗅探技术监听总线的传播的数据来检测自己缓存的数据是否失效。处理器对于失效的数据需要从主内存内重新加载到处理器的缓存内。

4)锁的类型和状态

锁的状态

作用

说明

无锁状态 锁状态的初始值  
偏向锁状态 线程获取的时候,设置对象头Mark Work内的偏向线程ID为当前线程的ID 默认启用,降低锁获取的代价
轻量级锁状态 当对象头Mark Work 内偏向线程ID不为当前线程ID设置为当前线程ID时  
重量级锁状态 存在多个线程竞争的时候,轻量级锁状态 晋升为 重量级锁状态  

锁的类型

优点

缺点

适用范围

偏向锁 加锁、解锁不需要额外的消耗 线程竞争的时候存在额外的锁撤销消耗 只有一个线程访问同步块的场景
轻量级锁 竞争线程不会阻塞,提高程序的响应速度 获取不到锁的线程自旋等待消耗CPU 追求响应时间
同步块代码执行速度快
重量级锁 线程竞争阻塞,不自旋消耗CPU 线程阻塞,响应时间慢 最求吞吐量
同步块代码执行速度较长

2、原子操作的实现原理

所谓的原子操作就是不可分割的最小单位的执行操作

(1)处理器如何实现原子操作

         1)总线锁定

         2)缓存锁定

(2)Java如何实现原子操作

          1)CAS算法

          2)加锁机制