模式切换
Java 并发编程基础
Java 并发编程是 Java 开发中非常重要的一部分,尤其是在多核 CPU 普及的今天,合理利用多线程可以显著提高程序的性能。
并发与并行的区别
并发(Concurrency)
并发是指多个任务在同一时间段内交替进行,从宏观的角度上看像是同时进行,但实际上是通过时间片轮转的方式交替执行。
在单核 CPU 中运行多个线程时,CPU 通过快速切换线程的方式实现并发。
并发可以提高系统的吞吐量,但不能提高单个任务的执行速度,并且可以提高资源利用率,使多个任务能够“同时”进行。
并行(Parallelism)
并行是指多个任务在同一时刻真正同时执行,通常需要多核 CPU 的支持。
在多核 CPU 上,每个核心可以独立执行一个线程,从而实现真正的并行。
并行可以提高任务执行速度,缩短整体运行的时间。
多核 CPU 与多线程的关系
- 多核 CPU 为并行计算提供了硬件支持,每个核心可以独立运行一个线程。
- 多线程编程可以充分利用多核 CPU 的计算能力,将任务分配到多个核心上并行执行。
- 并发编程的目标是编写能够同时处理多个任务的程序,而并行是实现并发的一种手段。
线程的基本概念
什么是线程?
线程是操作系统调度的最小单位,是进城中的一个执行流。
一个进程可以包含多个线程,线程之间共享进程的内存空间(堆、方法区),但每个线程有自己的栈和程序计数器。
线程是轻量级的,创建和切换线程的开销比进程小。
线程的生命周期
线程的生命周期包含以下几个状态:
- 新建(New):线程对象被创建,但尚未调用
start()
方法。 - 就绪(Runnable):线程调用
start()
方法后,等待 CPU 调度。 - 运行(Running):线程获得 CPU 时间片,正在执行
run()
方法。 - 阻塞(Blocked):线程因为某种原因(如等待锁、I/O 操作等)暂时停止执行。
- 终止(Terminated):线程执行完
run()
方法,或者因异常退出。
线程的创建方式
- 继承
Thread
类。
定义一个类继承 Thread
类,并重写 run()
方法。
java
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running");
}
}
MyThread thread = new MyThread();
thread.start();
- 实现
Runnable
接口。
定义一个类实现 Runnable
接口,并实现 run()
方法。
java
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread is running");
}
}
Thread thread = new Thread(new MyRunnable());
thread.start();
- 实现
Callable
接口。
Callable
与Runnable
类似,但可以返回结果或抛出异常。需要配合
FutureTask
或线程池使用。javaclass MyCallable implements Callable<String> { @Override public String call() throws Exception { return "Thread is running"; } } FutureTask<String> futureTask = new FutureTask<>(new MyCallable()); Thread thread = new Thread(futureTask); thread.start(); System.out.println(futureTask.get()); // 获取返回值
线程的启动、暂停、中断和终止
- 启动:调用
start()
方法,线程进入就绪状态。 - 暂停:使用
sleep()
方法让线程暂停一段时间。 - 中断:调用
interrupt()
方法中断线程。 - 终止:线程执行完
run()
方法或抛出未捕获的异常时终止。
线程的基本操作
常用方法
start()
:启动线程,使其进入就绪状态。run()
:线程的执行逻辑,需要重写。join()
:等待线程执行完毕。
java
Thread thread = new Thread(() -> System.out.println("Thread is running"));
thread.start();
thread.join(); // 主线程等待 thread 执行完毕
sleep(long millis)
:让当前线程暂停指定时间(毫秒)。
java
Thread.sleep(1000); // 暂停 1 秒
yield()
:让出 CPU 时间片,使当前线程进入就绪状态,让其他线程有机会执行。
线程的中断机制
interrupt()
:终端线程,设置线程的中断标志。isInterrupted()
:检查线程是否被中断。interrupted()
:检查线程是否被中断,并清除中断标志。
java
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Thread is running");
}
});
thread.start();
Thread.sleep(1000);
thread.interrupt(); // 中断线程
线程的优先级
线程优先级的设置与作用
线程优先级是一个整数,范围从 1(最低)到 10(最高),默认为 5。
在下方示例中,展示了如何设置线程优先级:
java
Thread thread = new Thread(() -> System.out.println("Thread is running"));
thread.setPriority(Thread.MAX_PRIORITY); // 设置为最高优先级
thread.start();
优先级对线程调用的影响
- 优先级高的线程有更大机会被 CPU 调度执行。
- 但优先级并不能保证线程的执行顺序,具体调度取决于操作系统的实现。
总结
- 并发是多个任务交替执行,并行是多个任务同时执行。
- 线程是程序执行的基本单位,可以通过继承
Thread
类、实现Runnable
接口或Callable
接口创建线程。 - 线程的生命周期包括:创建、就绪、运行、阻塞和终止。
- 线程的基本操作包括:启动、暂停、中断和终止。
- 线程的优先级可以影响线程的调度,但不能完全控制执行顺序。