线程的创建方式与生命周期

线程的创建方式与生命周期

线程是 Java 并发编程的基础单元。本文系统讲解线程的创建、状态和生命周期管理。

线程的三种创建方式

1. 继承 Thread 类

public class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行: " + Thread.currentThread().getName());
}
}

// 使用
MyThread thread = new MyThread();
thread.start();

缺点:Java 单继承限制,无法继承其他类。

2. 实现 Runnable 接口

public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程执行: " + Thread.currentThread().getName());
}
}

// 使用
Thread thread = new Thread(new MyRunnable());
thread.start();

// Lambda 简化
Thread thread2 = new Thread(() -> System.out.println("线程执行"));
thread2.start();

优点:解耦任务和线程,更灵活。

3. 实现 Callable 接口

public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "任务完成";
}
}

// 使用
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
new Thread(futureTask).start();

String result = futureTask.get(); // 阻塞等待结果
System.out.println(result);

特点:可以返回值,可以抛出异常。

三种方式对比

方式 返回值 异常 灵活性
Thread 内部处理
Runnable 内部处理
Callable 可抛出

线程的六种状态

public enum State {
NEW, // 新建
RUNNABLE, // 可运行
BLOCKED, // 阻塞
WAITING, // 等待
TIMED_WAITING, // 限时等待
TERMINATED // 终止
}

状态转换图

NEW -> start() -> RUNNABLE <-> 获取锁失败 -> BLOCKED -> 获取锁 -> RUNNABLE
|
|-> wait() -> WAITING -> notify()/notifyAll() -> RUNNABLE
|
|-> sleep(time)/wait(time)/join(time) -> TIMED_WAITING -> 时间到 -> RUNNABLE
|
|-> 执行完毕/异常 -> TERMINATED

各状态详解

NEW(新建)

Thread t = new Thread(() -> {});
System.out.println(t.getState()); // NEW

线程被创建,未调用 start()。

RUNNABLE(可运行)

Thread t = new Thread(() -> {
while (true) {} // 占用CPU
});
t.start();
System.out.println(t.getState()); // RUNNABLE

包含操作系统层面的 Running 和 Ready 状态。

BLOCKED(阻塞)

Object lock = new Object();

Thread t1 = new Thread(() -> {
synchronized (lock) {
try { Thread.sleep(10000); } catch (InterruptedException e) {}
}
});

Thread t2 = new Thread(() -> {
synchronized (lock) { // 阻塞等待t1释放锁
}
});

t1.start();
t2.start();
Thread.sleep(100);
System.out.println(t2.getState()); // BLOCKED

等待获取监视器锁(synchronized)。

WAITING(等待)

Object lock = new Object();

Thread t = new Thread(() -> {
synchronized (lock) {
try {
lock.wait(); // 释放锁,进入WAITING
} catch (InterruptedException e) {}
}
});

t.start();
Thread.sleep(100);
System.out.println(t.getState()); // WAITING

无限期等待,需要被唤醒:

  • Object.wait()
  • Thread.join()
  • LockSupport.park()

TIMED_WAITING(限时等待)

Thread t = new Thread(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {}
});

t.start();
Thread.sleep(100);
System.out.println(t.getState()); // TIMED_WAITING

限时等待,时间到自动恢复:

  • Thread.sleep(long)
  • Object.wait(long)
  • Thread.join(long)
  • LockSupport.parkNanos(long)
  • LockSupport.parkUntil(long)

TERMINATED(终止)

Thread t = new Thread(() -> {});
t.start();
t.join();
System.out.println(t.getState()); // TERMINATED

线程执行完毕或异常退出。

线程基本操作

启动与中断

Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
// 执行任务
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 收到中断信号,退出循环
Thread.currentThread().interrupt(); // 重新设置中断标志
break;
}
}
});

t.start();
// ...
t.interrupt(); // 请求中断线程

等待与通知

Object lock = new Object();
boolean flag = false;

// 等待线程
Thread waiter = new Thread(() -> {
synchronized (lock) {
while (!flag) { // 防止虚假唤醒
try {
lock.wait();
} catch (InterruptedException e) {}
}
System.out.println("条件满足,继续执行");
}
});

// 通知线程
Thread notifier = new Thread(() -> {
synchronized (lock) {
flag = true;
lock.notifyAll(); // 唤醒所有等待线程
}
});

守护线程

Thread daemon = new Thread(() -> {
while (true) {
System.out.println("守护线程运行中...");
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
});
daemon.setDaemon(true); // 设置为守护线程
daemon.start();

// 主线程结束,守护线程自动终止

特点

  • 后台服务线程(如垃圾回收线程)
  • 所有非守护线程结束后,JVM 自动退出
  • 守护线程不能持有需要关闭的资源

线程优先级

Thread t = new Thread(() -> {});
t.setPriority(Thread.MAX_PRIORITY); // 10
// Thread.NORM_PRIORITY = 5
// Thread.MIN_PRIORITY = 1

注意:优先级只是提示,具体调度取决于操作系统,不可靠。

最佳实践

  1. 优先使用 Runnable/Callable:解耦任务和线程
  2. 正确响应中断:不要忽略 InterruptedException
  3. 使用线程池:不要直接创建 Thread
  4. 避免使用 stop/suspend/resume:已废弃,不安全
  5. 守护线程不持有资源:防止资源泄漏
// 好的做法:使用线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
Future<String> future = executor.submit(() -> {
return "任务结果";
});
String result = future.get();
executor.shutdown();

总结

理解线程的生命周期和状态转换是并发编程的基础。在实际开发中,应尽量使用线程池和并发工具类,避免直接操作 Thread 对象。


   转载规则


《线程的创建方式与生命周期》 小乐 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录