Skip to main content

基本概念

线程(Thread)

  • 线程是操作系统中能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
  • 在JVM中,线程有独立的程序计数器和栈空间,多个线程共享方法区和堆空间

进程(Process)

  • 进程是操作系统中正在运行的一个程序实例。每个进程都拥有独立的内存空间,包含程序的代码、数据和运行时资源。Java程序本身也是一个进程,而Java虚拟机(JVM)则是在操作系统进程中运行的。

并发(Concurrency)

  • 并发是指系统中同时存在多个线程(或进程)在执行。在多核CPU上,并发可以通过真正的并行执行来提高程序的性能。

同步(Synchronization)

  • 同步是指多个线程之间按照一定的顺序执行,以确保共享资源的正确访问,用锁来实现

异步(Asynchronization)

  • 异步是指多个任务之间相互独立,不需要按照固定的顺序执行

原子性(Atomicity)

  • 原子性是指操作不可分割,要么全部执行成功,要么全部不执行。在并发编程中,原子操作是指一个或一组操作在执行过程中不会被中断的特性。

可见性(Visibility)

  • 可见性是指一个线程对共享变量的修改能够及时地被其他线程看到。在Java中,可以使用volatile关键字来保证变量的可见性。

有序性(Ordering)

  • 有序性是指程序执行的顺序和代码的编写顺序一致。在多线程环境下,由于指令重排序等优化,可能会导致代码执行顺序与预期不符,因此需要通过同步机制来保证有序性。

Java内存模型

The Java memory model describes how threads in the Java programming language interact through memory. Together with the description of single-threaded execution of code, the memory model provides the semantics of the Java programming language.

The Java Memory Model describes what behaviors are legal in multithreaded code, and how threads may interact through memory. It describes the relationship between variables in a program and the low-level details of storing and retrieving them to and from memory or registers in a real computer system. It does this in a way that can be implemented correctly using a wide variety of hardware and a wide variety of compiler optimizations. https://www.cs.umd.edu/%7Epugh/java/memoryModel

描述了多线程代码中哪些行为是合法的,以及线程如何通过内存进行交互。 它描述了程序中变量之间的关系以及在真实计算机系统中的内存或寄存器中存储和检索变量的低级细节。它以一种可以使用各种硬件和各种编译器优化来正确实现的方式来实现这一点。

  • 共享内存和本地内存
    • 共享内存对应jvm堆的一部分
    • 本地内存是一个抽象的概念,覆盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化
  • 重排序(reordering)
    • 编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。
    • 重排序会导致代码执行顺序与预期不符,因此需要通过同步机制来保证有序性。
    • 或者通过Happens-Before机制来保证有序性。
  • Happens-Before
    • Each action in a thread happens before every action in that thread that comes later in the program's order. 单一线程中的每个操作都发生在该线程中按程序顺序排列较晚的每个操作之前。 (仅仅是保证语义上的结果的正确性)
    • An unlock on a monitor happens before every subsequent lock on that same monitor. 监视器上的解锁发生在同一监视器上的每个后续锁定之前。
    • A write to a volatile field happens before every subsequent read of that same volatile. 对volatile字段的写入发生在每次后续读取同一volatile字段之前。
    • A call to start() on a thread happens before any actions in the started thread. 线程上对 start() 的调用发生在已启动线程中的任何操作之前。
    • All actions in a thread happen before any other thread successfully returns from a join() on that thread. 线程中的所有操作都会在任何其他线程从该线程上的 join() 成功返回之前发生。
  • volatile
    • 在JSR 133(JDK 5.0)中被加强过语义,保证可见性和禁止指令重排序
  • final
    • 表示不可变性,其修饰的类不能被继承,修饰的变量只能被初始化一次,不能被改变(基本类型赋值后不能再次赋值,引用类型引用地址不能改,对象本身的属性能改)
    • 对final字段的写一定要在构造函数里
    • 重排序:
      • 对final字段的赋值,在该字段所属的对象构造并赋给一个变量之前。
      • 对final字段的读操作发生在该变量被赋值之后。
      • 对于引用类型,jvm可以保证,在构造函数里,对final修饰的引用类型的属性修改,在读这个final字段之前
  • 延迟初始化的单例模式(双重校验)
  class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
//第一次校验,不是null就直接放过,防止已经初始化的情况下加锁,这样能在无锁的低成本下,过滤掉大多数情况
if (helper == null) {
//防止分配多个对象
synchronized(this) {
//第二次校验,同步保证只有一个对象,防止在第一次校验到同步中间,helper已经被赋值了
if (helper == null)
//伪代码:
//1.分配对象的内存空间,2.初始化对象,3.设置对象指向分配的内存地址
//会乱序所以加上volatile,防止第一次校验后helper没有被赋值
helper = new Helper();
}
}
return helper;
}
}
  • 基于内部类实现的单例
class Foo {
private static class HelperHolder {
public static Helper helper = new Helper();
}
public static Helper getHelper() {
return HelperHolder.helper ;  // 这里将导致HelperHolder类被初始化,类加载器是线程安全的
}
}

Q&A