1.串行、并发与并行

图片.png
图片.png

从软件的角度来说,并发就是在一段时间内以交替的方式去完成多个任务,而并行就是以齐头并进的方式去完成多个任务


2.竞态

图片.png图片.png竞态的两种模式

  • **read-modify-write**:读-改-写
  • **check-then-act**:检测而后行动

3.线程安全性

一般而言,如果一个类在单线程环境下能够运行正常,并且在多线程环境下,不必为其做任何改变也能正常运行,就称这个类具有线程安全性。
一个类如果能导致竞态,那么它就是非线程安全的

Java标准库中的一些类,如ArrayList、HashMap和SimpleDateFormat都是非线程安全的

比如,多线程环境下共享同一个HashMap实例,可能会导致死循环和内存泄漏


4.原子性

原子(Atomic)的字面意思是 不可分割 的(indivisible)

图片.png

注意:原子操作是针对访问共享变量的操作而言的。也就是说,仅仅设计局部变量访问的操作都是原子操作

实现原子性:

  1. 使用锁(Lock):锁具有排他性,它能够保障一个共享变量在任意一个时刻只能够被一个线程访问,这就排除了多个线程在同一时刻访问同一个共享变量而导致干扰与冲突的可能,消除了竞态。
  2. 利用处理器提供的专门CAS(Compare-and-Swap)指令:与锁实现原子性的方式实质上相同,差别在于锁是在软件层面实现的,而CAS是硬件层面,又叫做“硬件锁”

图片.png

在多个线程并发访问同一long/double型变量的情况下,一个线程可能会读取到其他线程更新该变量的“中间结果”

图片.png

注意:原子操作+原子操作 != 原子操作


5.可见性

图片.png图片.png

可见性的保障仅仅意味着一个线程能够读取到共享变量的相对新值,而不能保障该线程能够读取到相应变量的最新值

*可见性拓展阅读(见书51)

图片.png
图片.png图片.png


Java语言规范的保证

  1. 保证父线程在启动子线程之前,对共享变量的更新对于子线程来说是可见的
  1. public class ThreadStartVisibility {
  2. //设置共享变量
  3. static int data = 0;
  4. public static void main(String[] args) throws InterruptedException {
  5. Thread thread = new Thread() {
  6. @Override
  7. public void run() {
  8. try {
  9. Thread.sleep(10);
  10. System.out.println(data);
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. };
  16. //语句1:在线程启动前修改data
  17. data = 1;
  18. thread.start();
  19. Thread.sleep(10);
  20. //语句2:启动后再改变data
  21. data = 2;
  22. }
  23. }

图片.png

  1. 保证一个线程终止后,该线程对共享变量的更新对于调用该线程的join方法的线程而言是可见的

    1. public class ThreadStartVisibility {
    2. //设置共享变量
    3. static int data = 0;
    4. public static void main(String[] args) throws InterruptedException {
    5. Thread thread = new Thread() {
    6. @Override
    7. public void run() {
    8. try {
    9. Thread.sleep(10);
    10. //更新data的值
    11. data=1;
    12. } catch (InterruptedException e) {
    13. e.printStackTrace();
    14. }
    15. }
    16. };
    17. thread.start();
    18. //等待线程Thread结束后,main线程才继续执行
    19. thread.join();
    20. System.out.println(data);
    21. }
    22. }

    图片.png


6.有序性

有序性(Ordering):在什么情况下一个处理器上运行的一个线程所执行的内存访问操作在另外一个处理器上运行的其他线程看来是乱序的,所谓乱序,是指内存访问操作的顺序看起来发生了变化

6.1重排序的概念

图片.png
图片.png

6.2可见性和有序性的区别和联系

图片.png


7.上下文切换

这里所讨论的上线文切换具体指的是线程的上下文切换,不讨论进程

7.1上下文切换以及产生的原因

图片.png

  • 切出(Switch Out):一个线程被剥夺处理器的使用权而被暂停运行
  • 切入(Switch In):一个线程被操作系统选中占用处理器开始或者继续其运行

图片.png


7.2上下文切换的分类和具体诱因

按照导致上下文切换的因素划分:

  • 自发性上下文切换

从Java平台的角度来看,一个线程在其运行过程中执行下列任意一个方法都会引起自发性上下文切换
图片.png
另外,线程发起了I/O操作或者等待其他线程持有的锁,也会导致

  • 非自发性上下文切换
  • 图片.png

7.3上下文切换的开销

直接开销:
图片.png
简介开销:
图片.png


8.线程的活性故障

图片.png
常见的活性故障
图片.png图片.png


9.资源争用和调度

排他性资源:一次只能够被一个线程占用的资源,如处理器、数据库连接、文件等
图片.png

非公平调度策略:先到不一定先得 公平调度策略:先到先得

图片.png


总结

图片.png