多线程基本知识
文章摘要: 本文介绍了线程的基础知识,包括线程与进程的区别(资源分配与CPU调度)、并发与并行的概念(应对vs执行多任务)。重点讲解了4种创建线程的方式:继承Thread类、实现Runnable/Callable接口(支持返回值)及线程池(推荐生产使用)。通过状态图说明线程生命周期(新建→可运行→阻塞/等待→终止),并对比了wait/sleep的异同(锁释放、唤醒机制)。最后给出保证线程顺序执行的
今天学习线程的基本知识
文章目录
总体学习大纲
1. 线程和进程区别??
进程是资源分配的最小单位,线程是 CPU 调度的最小单位。
- 进程是资源的容器,线程是干活的人。
- 进程是为了隔离(防止互相干扰),线程是为了共享(提高效率)。
2. 并发与并行区别??
并发(concurrent)是同一时间应对(dealing with)多件事情的能力
比如说:
处理一件事情,一个处理时间10分钟, 并发下,5个人处理这件事(5个线程),只需要两分钟。
并行(parallel)是同一时间动手做(doing)多件事情的能力
比如说:
我一个人同一时间内可以处理5件事情
3. 创建线程的方式有哪些???(高频)
- 继承Thread类,从写run方法
- 实现Runnable接口,从写run方法,但是使用方式有点不一样
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程通过实现Runnable接口运行");
}
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
- 实现 Callable 接口 + FutureTask
如果你的线程任务需要返回结果或抛出异常,就用这种方式。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
// 任务执行后返回结果
return "线程通过Callable接口运行,返回结果";
}
public static void main(String[] args) throws Exception {
Callable<String> callable = new MyCallable();
FutureTask<String> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
// 获取线程执行结果(会阻塞直到结果返回)
String result = futureTask.get();
System.out.println(result);
}
}
核心优势: 支持返回值和异常捕获,适合需要任务结果的场景(如计算型任务)。
- 使用线程池(最推荐在生产环境使用)
直接创建线程会频繁产生创建 / 销毁的开销,线程池可以复用线程,提高性能。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 创建固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交任务给线程池
for (int i = 0; i < 5; i++) {
executor.submit(() -> {
System.out.println("线程池中的线程运行:" + Thread.currentThread().getName());
});
}
// 关闭线程池
executor.shutdown();
}
}
项目中用
3.1 创建线程方法runnable和callable
- Runnable接口的run没有返回值
- Callable接口的call方法有返回值,可以获取异步执行结果
- Callable接口的call()方法允许抛出异常; 而Runnable接口的run()方法不可以向上抛出异常。
3.2 run方法和start方法区别
run方法只是普通方法,可以调用多次
start方法是启动该线程,启动后该代码就会执行run方法的任务,该线程不可以启动多次
4. 线程包括那些状态,状态是如何变化的??
线程状态在Thread类中的枚举State内部类

线程状态包括: 新建(new), 可运行(RUNNAbLE), 阻塞(BLOCKED),等待(WAITNG),时间等待(TIME_WALTING),终止(TERMINATED)。
状态的转换关系
- 创建线程对象是新建状态
- 调用了 start () 方法转变为可执行状态
- 线程获取到了 CPU 的执行权,执行结束是终止状态
- 在可执行状态的过程中,如果没有获取 CPU 的执行权,可能会切换其他状态
- 如果没有获取锁(synchronized 或 lock)进入阻塞状态,获得锁再切换为可执行状态
- 如果线程调用了 wait () 方法进入等待状态,其他线程调用 notify () 唤醒后可切换为可执行状态
- 如果线程调用了 sleep (50) 方法,进入计时等待状态,到时间后可切换为可执行状态
5. 新建T1,T2,T3三个线程,如何保证他们的执行顺序??
方法一:join()方法
6. notify和notifyAll方法的区别???
-
notifyAll唤醒所有wait线程
-
notify唤醒所有wait线程
7. Java中的wait和sleep方法的不同???(高频)
wait () 的重载方法:
- wait():无限等待,直到被唤醒;
- wait(long timeout):超时自动唤醒(单位:毫秒),避免永久等待。
sleep () 的参数:
- sleep(long millis):休眠指定毫秒;
- sleep(long millis, int nanos):精确到纳秒(实际很少用)。
共同点
- 都会让当前线程暂停一段时间,进入阻塞状态。
- 都支持超时参数(wait(long timeout) 和 sleep(long millis)),可以在指定时间后自动恢复执行。
不同点 - wait是java.lang.Object的方法, sleep是java.lang.Thread的方法
- wait必须在 synchronized 块中调用,且会释放持有的对象锁。sleep无需持有锁,调用时不会释放任何锁。
- wait必须其他线程调用 notify()/notifyAll() 唤醒,或超时自动唤醒。sleep到达指定时间自动唤醒,或被中断唤醒。
8. 如何停止一个正在运行的线程???
两种方式:
「自定义标记」方式
原理: 通过一个共享的布尔变量作为停止标记,线程在循环中检查该变量,为 true 时主动退出。
注意: 标记变量需要用 volatile 修饰,确保多线程之间的可见性。
public class FlagDemo {
// 用volatile保证可见性
private static volatile boolean stopFlag = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (!stopFlag) {
System.out.println("线程运行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程已停止");
});
thread.start();
// 3秒后设置停止标记
Thread.sleep(3000);
stopFlag = true;
}
}
「中断标记」方式(最常用)
原理: 线程通过 isInterrupted() 方法检查中断标记,在合适的时机主动退出。
触发中断: 其他线程调用 thread.interrupt() 时,会给目标线程设置一个中断标记。
处理中断: 如果线程在 wait()、sleep() 等阻塞方法中被中断,会抛出 InterruptedException,此时需要捕获异常并退出循环。
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
// 循环中检查中断标记
while (!Thread.currentThread().isInterrupted()) {
System.out.println("线程运行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 捕获中断异常后,需要手动退出循环
System.out.println("线程被中断,准备退出");
break;
}
}
System.out.println("线程已停止");
});
thread.start();
// 3秒后中断线程
Thread.sleep(3000);
thread.interrupt();
}
}
好了线程基础就到这里
更多推荐


所有评论(0)