多线程基础

详细介绍多线程基础

Posted by chengweii on October 30, 2017

Thread

线程表示程序的执行流程,是CPU调度执行的基本单位;线程有自己的程序计数器、寄存器、堆栈和帧。同一进程中的线程共用相同的地址空间,同时共享进程所拥有的内存和其他资源。

线程内存模型

Java内存模型规定了所有的变量都存储在主内存中,此处的主内存仅仅是虚拟机内存的一部分,而虚拟机内存也仅仅是计算机物理内存的一部分(为虚拟机进程分配的那一部分)。 每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝。线程对变量的所有操作(读取、赋值),都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成,线程、主内存、工作内存三者之间的交互关系如下图: 线程内存模型

数据的共享与私有

由线程的内存模型可知,主内存的变量

线程状态

线程状态切换

线程状态切换

线程安全

当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用方法代码时不必做其他的协调,这个类的行为仍是正确的,那么称这个类是线程安全的。

并发问题

原子性问题

long和double的赋值、i++操作

  • 竞争条件
    • 检查再运行
    • 复合操作

可见性问题

  • 无状态对象永远是线程安全的

原子性

原子类

  • AtomicBoolean、AtomicInteger、AtomicIntegerArray、AtomicLong、AtomicLongArray、AtomicReference、AtomicReferenceArray、AtomicMarkableReference、AtomicStampedReference、AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater等
    • CAS算法

      AQS

对象锁、类锁(特殊对象锁)
自旋锁、阻塞锁、可重入锁

同步(锁控制)

同步操作不止是控制线程执行的顺序,还会自动从主内存中更新工作内存中的共享变量的数据。

synchronized、wait、notify、notifyAll

wait隶属于对象,该操作会释放锁,将当前线程放入对象的等待池中

ReentrantLock与ReentrantReadWriteLock
join(wait、notify实现)

把指定的线程加入到当前线程之前执行,可以将两个交替执行的线程合并为顺序执行的线程。

死锁

可见性

  • 非原子性读写问题
  • 代码重排序问题

解决方案

volatile

volatile修饰的变量的获取会强制线程同步在主内存的变量数据到工作内存中。

注意:实际中发现线程阻塞操作如:Thread.sleep()、IO、synchronized、等待另一个线程的计算结果等也会自动同步主内存的变量数据到工作内存中。

  • 未声明为volatile的long和double的变量访问数据可能不完整(由于这类变量的读写是非原子的在64位系统下)
加锁

线程切换

  • IO等阻塞操作会使JVM将当前线程移出调度队列,直至IO结束,然而阻塞操作完成后,当前线程不一定会继续获得执行权,这时很可能会发生线程切换。

线程通信

线程间通信

线程内通信

ThreadLocal

InheritableThreadLocal

性能和可伸缩性

减少锁的竞争

减少锁的时间

  • 同步块的代码越少越好

减小锁的粒度

  • ConcurrentHashMap hash bucket 16个锁 n%16

减少上下文切换的开销

并发应用

线程池

多线程面试题

什么是线程安全?

当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用方法代码时不必做其他的协调,这个类的行为仍是正确的,那么称这个类是线程安全的。

ConcurrentHashMap的原理?

SimpleDateFormat存在线程安全问题吗?

在设计工具类时为了效率,会将其设计为单例对象,但是DateFormat 和 SimpleDateFormat 类不都是线程安全的,在多线程环境下调用 format() 和 parse() 方法应该使用同步代码来避免问题(该方法中涉及操作对象成员变量calendar)。解决办法包括:

  • 需要的时候创建新实例
  • 使用同步:同步SimpleDateFormat对象
  • 使用ThreadLocal

参考文献

Java内存模型与Java线程的实现原理
JAVA CAS原理深度分析
源码剖析AQS在几个同步工具类中的使用
JUC回顾之-AQS同步器的实现原理
JUC回顾之-Semaphore底层实现和原理
JUC回顾之-CyclicBarrier底层实现和原理
深入理解Java:SimpleDateFormat安全的时间格式化