进程、线程和协程

并发和并行

并发就是同一时刻只有一条指令在执行,但由于CPU时间片很小,多个指令间能快速切换,宏观上形成同时执行的效果。

并行则是真正意义上的同时进行。

并发三要素

  • 原子性:在一个操作中,CPU 不可以在中途暂停然后再调度,即不被中断操作,要么执行完成,要么就不执行
  • 可见性:多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值
  • 有序性:程序执行的顺序按照代码的先后顺序执行

线程和进程的区别

  • 进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
  • 每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小
  • 一个进程可以有多个线程,至少有一个主线程
  • 一个进程崩溃后,在保护模式下不会对其他进程产生影响;但一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

Q:为什么进程切换的消耗比线程切换大?

A:

进程拥有独立的内存空间和资源管理机制,每次切换时需要保存和恢复更多的上下文信息;
而线程共享同一进程的内存和大部分资源,切换时涉及的上下文信息较少。
且进程切换更多发生在内核态,而同一进程内的线程切换更多发生在用户态,因此开销相对较小。

多进程和多线程分别有何优势?

  • 线程之间可以更轻松的共享数据
  • 系统创建进程需要为该进程重新分配系统资源,故创建线程代价比较小
  • 线程崩溃可能导致整个进程崩溃,而进程崩溃不会影响到另一个进程

哪些是线程共享的?

线程共享:

  • 全局变量和堆
  • 文件描述符,包括打开的文件、网络连接、输入输出流等,这些都是进程级别的资源

Q:Java三种创建线程的方法有什么区别?

A:

……

Java中锁的类型

  • 悲观锁乐观锁:悲观锁总是认为其他线程会修改数据,因此每次操作都上锁,如synchronized;乐观锁则假设其他线程不会修改数据,不上锁,如CAS
  • 公平锁非公平锁:公平锁按申请锁的顺序获取,如ReentrantLock;非公平锁不保证顺序
  • 自旋锁:线程循环等待直到获取锁
  • 可重入锁不可重入锁:可重入锁允许内层使用锁,不会产生死锁;不可重入锁不允许
  • 共享锁/读锁独享锁/写锁:共享锁允许多个执行单元同时获取锁,独享锁只允许一个

线程池

Java 多线程:彻底搞懂线程池

继承关系

ThreadPoolExecutor的参数:

参数名 是否必需 数据类型
说明
corePoolSize 必需 int 线程池的核心线程数
maximumPoolSize 必需 int 线程池的最大线程数
keepAliveTime 必需 long 当线程数大于核心线程数时,多余的空闲线程存活的最长时间
unit 必需 TimeUnit keepAliveTime的时间单位
workQueue 必需 BlockingQueue<Runnable> 决定线程池的任务队列的类型
threadFactory 可选 ThreadFactory 用于指定为线程池创建新线程的方式
handler 可选 RejectedExecutionHandler 拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务

线程池工作流程图

几种常见的内置线程池