Java 进程 vs 线程
本文介绍了进程与线程的核心概念及其在Java中的实现方式。主要内容包括: 进程与线程的区别:进程是操作系统资源分配的基本单位,拥有独立内存空间;线程是CPU调度的基本单位,共享进程资源,开销更小。 Java线程的4种创建方式: 继承Thread类 实现Runnable接口(推荐) 实现Callable接口(带返回值) 使用线程池(实际开发首选) 线程的6种生命周期状态:NEW、RUNNABLE、B
·
一、核心概念:进程 vs 线程
1. 进程(Process)
进程是操作系统分配资源的基本单位,是程序的一次运行实例。简单来说:
- 你双击运行一个 Java 程序(
java -jar app.jar),操作系统会为这个程序创建一个独立的 JVM 进程; - 每个进程拥有独立的内存空间(代码段、数据段、堆、文件句柄等),进程间相互隔离,通信成本高;
- 进程是 “重量级” 的,创建 / 销毁 / 切换的系统开销大。
Java 中操作进程:可以通过 Runtime.exec() 或 ProcessBuilder 创建子进程(比如调用系统命令、启动另一个程序),示例:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ProcessDemo {
public static void main(String[] args) throws Exception {
// 创建进程执行系统命令(Windows 用 dir,Linux/Mac 用 ls)
ProcessBuilder pb = new ProcessBuilder("ls", "-l");
Process process = pb.start();
// 读取进程输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// 等待进程结束并获取退出码
int exitCode = process.waitFor();
System.out.println("进程退出码:" + exitCode);
}
}
2. 线程(Thread)
线程是CPU 调度和执行的基本单位,也叫 “轻量级进程”,隶属于进程:
- 一个进程可以包含多个线程,所有线程共享进程的内存资源(堆、方法区),但每个线程有自己的栈空间和程序计数器(记录当前执行的指令);
- 线程是 “轻量级” 的,创建 / 销毁 / 切换的系统开销远小于进程;
- Java 程序的运行本质是 JVM 进程内多个线程的协作(比如主线程、GC 线程、JIT 编译线程)。
3. 进程与线程的核心区别
| 维度 | 进程 | 线程 |
|---|---|---|
| 资源分配 | 操作系统分配资源的单位 | 共享所属进程的资源 |
| 独立性 | 独立内存空间,相互隔离 | 共享内存,耦合度高 |
| 系统开销 | 大(创建 / 销毁 / 切换) | 小 |
| 通信方式 | 管道、套接字、文件等 | 共享变量、锁、队列等 |
| 调度单位 | 操作系统调度进程 | CPU 调度线程 |
二、Java 中线程的核心知识点
1. 线程的创建方式(4 种)
Java 中创建线程有 4 种常用方式,其中线程池是实际开发的首选:
方式 1:继承 Thread 类(重写 run () 方法)
// 步骤:1. 继承 Thread;2. 重写 run()(线程执行逻辑);3. 调用 start() 启动
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
}
public class ThreadCreate1 {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.setName("线程1");
t1.start(); // 启动线程(底层调用 native 方法启动系统线程)
MyThread t2 = new MyThread();
t2.setName("线程2");
t2.start();
}
}
方式 2:实现 Runnable 接口(解耦,推荐)
// 步骤:1. 实现 Runnable;2. 重写 run();3. 传入 Thread 构造器,调用 start()
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
}
public class ThreadCreate2 {
public static void main(String[] args) {
Runnable runnable = new MyRunnable();
Thread t1 = new Thread(runnable, "线程1");
Thread t2 = new Thread(runnable, "线程2");
t1.start();
t2.start();
}
}
方式 3:实现 Callable 接口(带返回值、可抛异常)
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
// 步骤:1. 实现 Callable;2. 重写 call()(带返回值);3. 包装为 FutureTask;4. 传入 Thread 启动
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
return sum;
}
}
public class ThreadCreate3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Integer> callable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread t = new Thread(futureTask, "计算线程");
t.start();
// 获取返回值(会阻塞直到线程执行完成)
Integer result = futureTask.get();
System.out.println("1-100 的和:" + result);
}
}
方式 4:线程池(Executor 框架,实际开发首选)
避免频繁创建 / 销毁线程的开销,控制并发数:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 创建固定大小的线程池(核心数=5)
ExecutorService executor = Executors.newFixedThreadPool(5);
// 提交 10 个任务
for (int i = 0; i < 10; i++) {
int taskNum = i;
executor.submit(() -> {
System.out.println(Thread.currentThread().getName() + " 执行任务 " + taskNum);
try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }
});
}
// 关闭线程池(先停止接收新任务,再等待已提交任务完成)
executor.shutdown();
}
}
2. 线程的生命周期(6 种状态)
Java 中 Thread.State 枚举定义了线程的 6 种状态,状态转换是线程的核心逻辑:
- NEW:线程对象已创建,但未调用
start(); - RUNNABLE:调用
start()后,线程处于 “就绪 / 运行” 状态(就绪:等待 CPU 调度;运行:正在执行); - BLOCKED:线程因竞争
synchronized锁而阻塞; - WAITING:线程无时限等待(如
Object.wait()、Thread.join()); - TIMED_WAITING:线程有时限等待(如
Thread.sleep(1000)、Object.wait(1000)); - TERMINATED:线程执行完成或异常终止。
3. 线程安全与同步
多个线程共享资源时会出现 “线程安全问题”(比如多线程卖票导致超卖),Java 提供了同步机制解决:
synchronized:关键字,可修饰方法 / 代码块,独占锁,自动释放;Lock接口(如ReentrantLock):手动锁,更灵活(可中断、超时获取锁);volatile:保证变量的可见性和禁止指令重排(但不保证原子性)。
示例(synchronized 解决卖票问题):
class Ticket {
private int count = 10; // 10 张票
// 同步方法:保证同一时间只有一个线程执行
public synchronized void sell() {
if (count > 0) {
System.out.println(Thread.currentThread().getName() + " 卖出第 " + count + " 张票");
count--;
}
}
}
public class TicketDemo {
public static void main(String[] args) {
Ticket ticket = new Ticket();
// 3 个线程卖票
for (int i = 0; i < 3; i++) {
new Thread(() -> {
for (int j = 0; j < 5; j++) {
ticket.sell();
try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
}
}, "窗口" + (i+1)).start();
}
}
}
三、总结
- 核心区别:进程是操作系统分配资源的单位,独立内存;线程是 CPU 调度的单位,共享进程资源,开销更小。
- Java 线程:创建方式有继承 Thread、实现 Runnable/Callable、线程池(推荐);有 6 种生命周期状态;通过 synchronized/Lock/volatile 保证线程安全。
- 实践建议:实际开发中优先使用线程池(而非手动创建线程),避免资源耗尽;多线程共享资源时必须处理线程安全问题。
更多推荐



所有评论(0)