目录
- 一、进程(Process)
- 二、线程(Thread)
- 三、线程的串行
- 四、多线程
- 五、多线程原理
- 六、多线程优缺点
- 七、Java 的默认线程
- 八、开启新线程
- (1) new Thread()
- (2) 继承 Thread,重写 run 方法
- (3) run() 和 start()
- 九、多线程的内存布局
- 十、线程的六种状态
- 十一、sleep、interrupt
一、进程(Process)
- 进程:操作系统中运行的应用程序
- 进程与进程之间是独立的
- 每个进程都运行在其专用且受保护的内存空间中
二、线程(Thread)
- 一个进程要想执行任务就必须要有线程(一个进程至少要有一个线程)
- 一个进程中的所有任务都在线程中执行
三、线程的串行
- 线程中任务的执行是串行的
- 若要在一个线程中执行多个任务,那么只能一个一个地按顺序地执行这些任务
- 同一时间内,一个线程只能执行一个任务
四、多线程
- 一个进程中可以开启多个线程、所有线程并行(同时)执行不同的任务
- 进程 👉 车间;线程 👉 车间工人
- 多线程技术可以提高程序的执行效率
五、多线程原理
- 同一时间,CPU 的一个核心只能处理一个线程(只有一个线程在工作)
- 多线程并发(同时)执行,其实是 CPU 快速地在多个线程之间调度(切换)
-
如果 CPU 调度线程的速度足够快,就造成了多条线程并发执行的假象
-
如果是多核 CPU,才是真正地实现了多个线程同时执行
-
若线程非常多:① CPU 将在多个线程之间来回调度,效率大量 CPU 资源;② 每条线程被调度执行地频次会降低(线程的执行效率会降低)
六、多线程优缺点
- 优点:① 能适当提高线程的执行效率;② 能适当提高资源利用率(CPU、内存利用率)
- 缺点:① 开启线程会占用一定的内存空间。若开启大量线程,会占用大量的内存空间,降低程序性能;② 线程越多,CPU 在调用线程上的开销越大
七、Java 的默认线程
-
每个 Java 程序启动后会默认开启一个线程,称为主线程(main 方法所在线程)
-
每一条线程都是一个
java.lang.Thread
对象,可通过Thread.currentThread
方法获取当前线程的线程(Thread) 对象
八、开启新线程
(1) new Thread()
public class QQTest {
public static void main(String[] args) {
// ① 创建了线程对象 musicThread
Thread musicThread = new Thread(new Runnable() {
@Override
public void run() {
// 这条线程中要执行的任务
System.out.println("\n播放音乐");
System.out.println(Thread.currentThread());
}
});
musicThread.setName("Thread-music");
musicThread.setPriority(10);
// ② 开启 musicThread 线程
musicThread.start();
}
}
(2) 继承 Thread,重写 run 方法
public class QQTest {
public static void main(String[] args) {
MusicThread musicThread = new MusicThread();
musicThread.setName("Music-Thread");
musicThread.start();
}
}
class MusicThread extends Thread {
@Override
public void run() {
// 该线程要执行的任务
System.out.println(getName() + "_播放音乐");
}
}
(3) run() 和 start()
public class QQTest {
public static void main(String[] args) {
Thread newThread = new Thread(() -> {
System.out.println(Thread.currentThread());
});
// Thread[Thread-0,5,main]
newThread.start();
// Thread[main,5,main]
newThread.run();
}
}
九、多线程的内存布局
① PC 寄存器(Program Counter Register):每个线程都有自己的 PC 寄存器。
PC 寄存器记录着 JVM 正在执行哪一条语句
② Java 虚拟机栈(Java Virtual Machine Stack):每个线程都有自己的 Java 虚拟机栈
③ 堆(Heap):多个线程共享堆空间
④ 方法区(Method Area):多个线程共享方法区
方法区放代码
⑤ 本地方法栈(Native Method Stack):每个线程都有自己的本地方法栈
十、线程的六种状态
- 可通过 Thread 对象的
getState()
获得线程的状态
① NEW(新建):尚未启动
② RUNNABLE(可运行状态):正在 JVM 中运行【或正在等待操作系统的其他资源(如:处理器)】
③ BLOCKED(阻塞状态):正在等待监视器锁(内部锁)
④ WAITING(等待状态):在等待另一个线程
调用以下方法会进入 WAITING 状态:
✏️ 没有超时值的:Object.wait
✏️ 没有超时值的:Thread.join
✏️ LockSupport.park
⑤ TIMED_WAITING(定时等待状态)
调用以下方法会进入 TIMED_WAITING状态:
✏️ Thread.sleep
✏️ 有超时值的:Object.wait
✏️ 有超时值的:Thread.join
✏️ LockSupport.parkNanos
✏️ LockSupport.parkUntil
⑥ TERMINATED(终止状态):已经执行完毕
public class QQTest {
public static void main(String[] args) {
// 主线程对象
Thread mainThread = Thread.currentThread();
// RUNNABLE
System.out.println(mainThread.getState().name());
// 子线程
Thread subThread = new Thread();
// NEW
System.out.println(subThread.getState().name());
}
}
十一、sleep、interrupt
-
可通过
Thread.sleep
方法暂停(睡眠)当前线程,进入 WAITING 状态 -
在暂停(睡眠)期间,若调用线程对象的 interrupt 方法中断线程,会抛出
java.lang.InterruptedException
public class QQTest {
public static void main(String[] args) {
Thread subThread = new Thread(() -> {
System.out.println("666");
try {
Thread.sleep(3333);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("520");
});
subThread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("111");
subThread.interrupt();
}
}