什么是JUC
JUC 是 java.util .concurrent 工具包的简称,是处理线程的工具包,从 Java1.5 开始出现。
进程和线程的概念
进程与线程
进程 ( process ) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
线程 ( thread ) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
进程状态
线程枚举类:
public enum State{
//新建状态
NEW;
//就绪状态
RUNNABLE;
//阻塞状态
BLOCKED;
//等待状态
WAITING;
//超时等待
TIME_WAITING;
//终止状态
TERMINATED;
}
- NEW(新建): 调用 new() 创建一个线程后,处于新建状态。此时该线程仅有 Java 虚拟机为其分配内存并初始化其成员变量,还没有表现出任何线程的动态特征。
- RUNNABLE(就绪): 当线程对象调用 start() 后,线程处于就绪状态。Java 虚拟机为其创建方法调用栈和程序计数器,等待JVM里的线程调度器调度。一旦获得 cup,则执行 run() 方法中的执行体。
- BLOCKED(阻塞): 线程执行过程中被中断,等待某个监视器锁的线程。当发生如下情况时,线程会进入阻塞状态:
- 线程调用了 sleep() 方法主动放弃占用的cpu资源;
- 线程调用了一个阻塞式 IO 方法,在该方法返回之前,该线程被阻塞;
- 线程试图获取一个同步监视器,但该同步监视器正被其他线程使用;
- 线程正在等待某一个通知;
- 程序调用了线程 susoend() 方法将该线程挂起。该方法容易造成死锁,不推荐使用。
-
WAITING(等待): 一个正在等待另一个线程执行的某一个操作的线程处于这一状态。
-
TIME_WAITING(超时等待): 一个正在限时等待另一个线程执行某一动作的线程处于这一状态。
-
TERMINATED(终止): 线程完成执行进入终止状态。
线程5种状态转换关系如下图所示:
wait() / sleep() 的区别
- sleep() 是 Thread 的静态方法,wait() 是 Object 的方法,任何对象实例都能调用。
- sleep() 不会释放锁,它也不需要占用锁。而 wait() 会释放锁,并需要通过 notify() / notifyAll() 重新获取锁。
- sleep() 可以在任何地方调用,而 wait() 只能在同步方法或同步代码块中调用。
并发与并行
串行模式: 串行表示所有任务都一一按先后顺序进行。串行是一次只能取得一个任务,并执行这个任务。
并行模式: 并行意味着可以同时取得多个任务,并同时去执行所取得的这些任务。并行的效率从代码层次上强依赖于多进程/多线程代码,从硬件角度上则依赖于多核 CPU。
并发: 并发 (concurrent) 指的是多个程序可以同时运行的现象,更细化的是多进程可以同时运行或者多指令可以同时运行。
并发:同一时刻多个线程在访问同一个资源,多个线程对一个点
例子:春运抢票 电商秒杀…
并行:多项工作一起执行,之后再汇总
例子:泡方便面,电水壶烧水,一边撕调料倒入桶中
管程
管程 (monitor) 是保证了同一时刻只有一个进程在管程内活动,即管程内定义的操作在同一时刻只被一个进程调用 (由编译器实现),但是这样并不能保证进程以设计的顺序执行。
JVM 中同步是基于进入和退出管程 (monitor) 对象实现的,每个对象都会有一个管程 (monitor) 对象,管程 (monitor) 会随着 java 对象一同创建和销毁。
执行线程首先要持有管程对象,然后才能执行方法,当方法完成之后会释放管程,方法在执行时候会持有管程,其他线程无法再获取同一个管程。
用户线程和守护线程
用户线程: 平时用到的普通线程,自定义线程。
守护线程: 运行在后台,是一种特殊的线程,比如垃圾回收。
当主线程结束后,用户线程还在运行,JVM 存活。如果没有用户线程,都是守护线程,JVM 结束