ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Java线程

2026/8/7 7:29:03 拓冰建站 浏览量
Java线程

当然可以!Java 中的线程是并发编程的核心,掌握好线程相关的知识对于开发高性能、高并发的应用程序非常重要。下面我将从 基础概念高级应用 系统地为你讲解 Java 中线程相关的全部知识。


🧵 Java 线程详解(完整版)


一、基本概念

1. 什么是线程?

  • 线程(Thread)是操作系统调度的最小单元。
  • 每个进程至少有一个主线程,Java 程序本身就是多线程运行的。
  • Java 中线程是轻量级的进程,多个线程共享同一个进程的资源(如堆内存),但拥有自己的栈空间。

2. 进程 vs 线程

对比项进程线程
资源开销开销大(独立内存空间)开销小(共享进程资源)
通信需要 IPC(进程间通信)机制共享内存,可以直接访问变量
调度操作系统调度JVM 和操作系统共同调度
安全性相互隔离,安全性高不隔离,一个线程出错可能影响整个进程

二、创建线程的方式

1. 继承 Thread

class MyThread extends Thread {@Overridepublic void run() {System.out.println("MyThread is running");}
}// 使用
MyThread t = new MyThread();
t.start(); // 启动线程

2. 实现 Runnable 接口(推荐)

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("MyRunnable is running");}
}// 使用
Thread t = new Thread(new MyRunnable());
t.start();

✅ 优势:Java不支持多继承,使用 Runnable 更灵活。

3. 使用 Lambda 表达式(Java 8+)

Thread thread = new Thread(() -> {System.out.println("Lambda thread running");
});
thread.start();

4. 使用 CallableFutureTask(可返回结果)

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;Callable<String> task = () -> {return "Result from Callable";
};FutureTask<String> futureTask = new FutureTask<>(task);
new Thread(futureTask).start();String result = futureTask.get(); // 获取线程执行结果
System.out.println(result);

一般来说,创建线程有很多种方式,例如继承Thread类、实现Runnable接口、实现Callable接口、使用线程池、使用CompletableFuture类等等。不过,这些方式其实并没有真正创建出线程。准确点来说,这些都属于是在 Java 代码中使用多线程的方法。严格来说,Java 就只有一种方式可以创建线程,那就是通过new Thread().start()创建。不管是哪种方式,最终还是依赖于new Thread().start()


三、线程状态和生命周期

Java 线程有以下几种状态(定义在 Thread.State 枚举中):

状态描述
NEW线程被创建但尚未启动
RUNNABLE正在 JVM 中执行,可能正在等待操作系统资源(如 CPU)
BLOCKED因为竞争锁而阻塞
WAITING无限期等待另一个线程执行特定动作
TIMED_WAITING在指定时间内等待
TERMINATED线程已结束

在这里插入图片描述
由上图可以看出:线程创建之后它将处于 NEW(新建) 状态,调用 start() 方法后开始运行,线程这时候处于 READY(可运行) 状态。可运行状态的线程获得了 CPU 时间片(timeslice)后就处于 RUNNING(运行) 状态。在操作系统层面,线程有 READY 和 RUNNING 状态;而在 JVM 层面,只能看到 RUNNABLE 状态(图源:HowToDoInJava:Java Thread Life Cycle and Thread States),所以 Java 系统一般将这两个状态统称为 RUNNABLE(运行中) 状态 。为什么 JVM 没有区分这两种状态呢? (摘自:Java 线程运行怎么有第六种状态? - Dawell 的回答 ) 现在的时分(time-sharing)多任务(multi-task)操作系统架构通常都是用所谓的“时间分片(time quantum or time slice)”方式进行抢占式(preemptive)轮转调度(round-robin 式)。这个时间分片通常是很小的,一个线程一次最多只能在 CPU 上运行比如 10-20ms 的时间(此时处于 running 状态),也即大概只有 0.01 秒这一量级,时间片用后就要被切换下来放入调度队列的末尾等待再次调度。(也即回到 ready 状态)。线程切换的如此之快,区分这两种状态就没什么意义了。
在这里插入图片描述
当线程执行 wait()方法之后,线程进入 WAITING(等待) 状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态。
TIMED_WAITING(超时等待) 状态相当于在等待状态的基础上增加了超时限制,比如通过 sleep(long millis)方法或 wait(long millis)方法可以将线程置于 TIMED_WAITING 状态。当超时时间结束后,线程将会返回到 RUNNABLE 状态。
当线程进入 synchronized 方法/块或者调用 wait 后(被 notify)重新进入 synchronized 方法/块,但是锁被其它线程占有,这个时候线程就会进入 BLOCKED(阻塞) 状态。
线程在执行完了 run()方法之后将会进入到 TERMINATED(终止) 状态。

四、线程常用方法

方法名功能说明
start()启动线程,调用其 run() 方法
run()线程体,需重写或实现
sleep(long millis)让当前线程休眠一段时间
join()等待该线程终止
yield()提示调度器当前线程愿意让出CPU时间片
interrupt()打断线程(设置中断标志位)
isInterrupted()检查线程是否被打断
getName(), setName()获取/设置线程名称
setPriority(int)设置线程优先级(1~10)
setDaemon(boolean)设置为守护线程(后台线程)

五、线程同步与并发控制

1. synchronized 关键字

用于保证同一时刻只有一个线程能进入临界区代码。

修饰方法
public synchronized void method() {// 同步方法
}
修饰代码块
synchronized (this) {// 同步代码块
}

2. Lock 接口(更灵活)

常见实现类:ReentrantLock

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;Lock lock = new ReentrantLock();lock.lock();
try {// 临界区代码
} finally {lock.unlock();
}

3. volatile 关键字

用于保证变量的可见性和禁止指令重排序,适用于状态标志等简单场景。

private volatile boolean flag = true;

4. 原子类(AtomicXXX)

AtomicInteger, AtomicBoolean 等,提供原子操作,避免加锁。

import java.util.concurrent.atomic.AtomicInteger;AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();

六、线程池

为什么要使用线程池?

  • 减少线程创建销毁的开销
  • 控制最大并发数
  • 提升系统响应速度

Java 提供的线程池工具类:Executors

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;ExecutorService executor = Executors.newFixedThreadPool(5);executor.submit(() -> {System.out.println("Task executed by thread pool");
});executor.shutdown(); // 关闭线程池

常见线程池类型:

线程池类型特点
newFixedThreadPool固定大小线程池,重复利用线程
newCachedThreadPool可缓存线程池,自动回收空闲线程
newSingleThreadExecutor单线程池,顺序执行任务
newScheduledThreadPool支持定时和周期性任务的线程池

七、线程通信

1. wait / notify / notifyAll

必须在 synchronized 块中使用:

synchronized (obj) {obj.wait(); // 当前线程释放锁并等待唤醒obj.notify(); // 唤醒一个等待线程obj.notifyAll(); // 唤醒所有等待线程
}

2. Condition(配合 Lock 使用)

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();lock.lock();
try {condition.await(); // 等待condition.signal(); // 唤醒
} finally {lock.unlock();
}

八、线程安全问题与解决方案

问题解决方案
数据竞争(Race Condition)加锁(synchronized、Lock)、原子类、volatile
内存可见性问题volatile、synchronized、final关键字
活锁、死锁、饥饿设计时规避、避免嵌套锁、公平锁等

九、守护线程(Daemon Thread)

  • 是一种“后台线程”,不影响JVM退出。
  • 主线程结束后,只要还有非守护线程在运行,JVM就不会退出。
Thread daemonThread = new Thread(() -> {while (true) {System.out.println("Daemon thread is running...");try {Thread.sleep(1000);} catch (InterruptedException e) {break;}}
});
daemonThread.setDaemon(true); // 设置为守护线程
daemonThread.start();

十、线程组(ThreadGroup)

用于对一组线程进行统一管理(如监控、中断等)。

ThreadGroup group = new ThreadGroup("MyGroup");Thread t1 = new Thread(group, () -> {System.out.println("In thread group");
});
t1.start();group.interrupt(); // 中断组内所有线程

十一、Fork/Join 框架(Java 7+)

适用于“分治”算法(如归并排序、并行计算)。

import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;class SumTask extends RecursiveTask<Integer> {private final int[] array;private final int start, end;public SumTask(int[] array, int start, int end) {this.array = array;this.start = start;this.end = end;}@Overrideprotected Integer compute() {if (end - start <= 10) {int sum = 0;for (int i = start; i < end; i++) {sum += array[i];}return sum;} else {int mid = (start + end) / 2;SumTask left = new SumTask(array, start, mid);SumTask right = new SumTask(array, mid, end);left.fork();right.fork();return left.join() + right.join();}}
}// 使用
int[] data = new int[1000];
ForkJoinPool pool = new ForkJoinPool();
int result = pool.invoke(new SumTask(data, 0, data.length));

十二、CompletableFuture(Java 8+)

用于异步编程,支持链式调用和组合操作。

import java.util.concurrent.CompletableFuture;CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {return "Hello";
});future.thenApply(s -> s + " World").thenAccept(System.out::println);

十三、线程局部变量(ThreadLocal)

每个线程拥有自己的副本,互不干扰。

ThreadLocal<Integer> local = new ThreadLocal<>();
local.set(100);
System.out.println(local.get()); // 每个线程获取自己的值

十四、实战建议

场景建议
多线程更新共享变量使用 synchronizedReentrantLockAtomicXXX
异步处理任务使用 ExecutorServiceCompletableFuture
并发集合操作使用 ConcurrentHashMapCopyOnWriteArrayList
简单状态标志使用 volatile
高性能并发读写使用 ReadWriteLock
防止死锁避免嵌套锁,按固定顺序加锁
线程复用使用线程池代替频繁新建线程