云计算百科
云计算领域专业知识百科平台

01 多线程初阶:解谜多线程世界

在日常开发中,你是否曾遇到这样的情景:应用程序需要执行多个任务,但你希望它们能够同时运行,以提高性能和响应性。这正是多线程编程的核心价值所在。

在本文中,我们将学习 Java 多线程编程的基础知识,包括线程的创建、使用、生命周期以及线程安全产生的原因。

一、线程创建与启动

线程是轻量级的,共享相同的进程内存空间。在 Java 中,线程可以使用 java.lang.Thread 类来创建和管理。

1. 实现 Runnable 接口

public class ThreadRunnableTest {
public static void main(String[] args) {
Thread thread = new Thread(new Task());
thread.setName("测试线程");
thread.start();
}
static class Task implements Runnable {
@Override
public void run() {
System.out.println("线程运行,线程名称为:" + Thread.currentThread().getName());
}
}
}

调用 start 方法后,主线程会开启一条子线程去执行任务,主线程继续向下执行,两者并行执行。

2. 实现 Callable 接口(有返回值)

public class ThreadCallableTest {
public static void main(String[] args) throws Exception {
FutureTask<String> stringFutureTask = new FutureTask<>(new TaskReturn());
Thread thread = new Thread(stringFutureTask);
thread.setName("测试线程");
thread.start();
System.out.println(stringFutureTask.get());
}
private static class TaskReturn implements Callable<String> {
@Override
public String call() {
return String.format("我被线程【%s】执行了", Thread.currentThread().getName());
}
}
}

Callable 无法直接传递到 Thread 中,需要使用 FutureTask 来包装。FutureTask 的 get 方法可以获取异步任务的执行结果。

主线程与子线程:点击运行后,执行 main 方法的线程称为主线程,从 main 方法中创建的线程称为子线程。

二、线程的主要参数与 API

1. 优先级

线程的优先级是一个整数值(1-10),1 表示最低优先级,10 表示最高优先级。

thread.setPriority(Thread.MAX_PRIORITY); // 设置为最高优先级

注意:线程优先级依赖于底层操作系统支持,不保证严格按照优先级顺序执行,且过度依赖可能导致不可预测的结果。

常见问题:

  • 优先级反转:低优先级线程持有锁后,高优先级线程等待时被阻塞
  • 饥饿:高优先级线程长期占用资源,低优先级线程无法获得执行机会

2. 线程名称

thread.setName("测试线程"); // 设置线程名称
Thread.currentThread().getName() // 获取当前线程名称

线程名称在排查问题(如死锁、系统变慢)时非常重要,可以使用 jconsole、jstack 等 JVM 工具监控。

3. 守护线程

守护线程的生命周期随主线程结束而终止,用于执行后台任务(如垃圾回收、定时任务、监控等)。

Thread thread = new Thread(new Task());
thread.setDaemon(true); // 设置为守护线程
thread.start();

守护线程 vs 工作线程:

  • 守护线程:主线程执行完毕,守护线程立即停止
  • 工作线程:JVM 会等待所有工作线程结束后才停止

注意:守护线程可能来不及执行资源回收(如关闭 JDBC 连接),需谨慎使用。

4. 停止线程

不推荐使用 thread.stop(),会导致资源不释放。

推荐使用 interrupt 方法请求线程停止:

public class StopThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Task());
thread.setName("测试线程");
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt(); // 发出停止信号
}
private static class Task implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("我执行了");
}
}
}
}

interrupt 方法会在线程等待条件时触发 InterruptedException 异常,需配合循环检测中断信号来终止线程。

三、线程生命周期和状态

Java 线程的生命周期包括以下状态:

状态说明
New 线程对象已创建,但尚未启动
Runnable 线程已准备好运行,等待 CPU 时间片
Running 线程获得 CPU 时间片并开始执行
Blocked 线程被阻塞,等待锁或其他条件
Waiting 线程等待其他线程通知继续执行
Timed Waiting 线程等待一段时间后自动唤醒
Terminated 线程生命周期结束

状态转换图:

#mermaid-svg-Gd7zbkcjVyeSU9ew{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Gd7zbkcjVyeSU9ew .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Gd7zbkcjVyeSU9ew .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Gd7zbkcjVyeSU9ew .error-icon{fill:#552222;}#mermaid-svg-Gd7zbkcjVyeSU9ew .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Gd7zbkcjVyeSU9ew .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Gd7zbkcjVyeSU9ew .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Gd7zbkcjVyeSU9ew .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Gd7zbkcjVyeSU9ew .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Gd7zbkcjVyeSU9ew .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Gd7zbkcjVyeSU9ew .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Gd7zbkcjVyeSU9ew .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Gd7zbkcjVyeSU9ew .marker.cross{stroke:#333333;}#mermaid-svg-Gd7zbkcjVyeSU9ew svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Gd7zbkcjVyeSU9ew p{margin:0;}#mermaid-svg-Gd7zbkcjVyeSU9ew defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-Gd7zbkcjVyeSU9ew g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-Gd7zbkcjVyeSU9ew g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-Gd7zbkcjVyeSU9ew g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-Gd7zbkcjVyeSU9ew g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-Gd7zbkcjVyeSU9ew g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-Gd7zbkcjVyeSU9ew .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-Gd7zbkcjVyeSU9ew .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-Gd7zbkcjVyeSU9ew .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-Gd7zbkcjVyeSU9ew .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Gd7zbkcjVyeSU9ew .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-Gd7zbkcjVyeSU9ew .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-Gd7zbkcjVyeSU9ew .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-Gd7zbkcjVyeSU9ew .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Gd7zbkcjVyeSU9ew .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Gd7zbkcjVyeSU9ew .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Gd7zbkcjVyeSU9ew .edgeLabel .label text{fill:#333;}#mermaid-svg-Gd7zbkcjVyeSU9ew .label div .edgeLabel{color:#333;}#mermaid-svg-Gd7zbkcjVyeSU9ew .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-Gd7zbkcjVyeSU9ew .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-Gd7zbkcjVyeSU9ew .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-Gd7zbkcjVyeSU9ew .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-Gd7zbkcjVyeSU9ew .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-Gd7zbkcjVyeSU9ew .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Gd7zbkcjVyeSU9ew .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Gd7zbkcjVyeSU9ew #statediagram-barbEnd{fill:#333333;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Gd7zbkcjVyeSU9ew .cluster-label,#mermaid-svg-Gd7zbkcjVyeSU9ew .nodeLabel{color:#131300;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-Gd7zbkcjVyeSU9ew .note-edge{stroke-dasharray:5;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-note text{fill:black;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram-note .nodeLabel{color:black;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagram .edgeLabel{color:red;}#mermaid-svg-Gd7zbkcjVyeSU9ew #dependencyStart,#mermaid-svg-Gd7zbkcjVyeSU9ew #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-Gd7zbkcjVyeSU9ew .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Gd7zbkcjVyeSU9ew :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

创建线程对象

start()

获得CPU时间片

等待锁

wait()

sleep()

获得锁

notify/notifyAll

时间到或notify

任务执行完毕

New

Runnable

Running

Blocked

Waiting

Timed_Waiting

Terminated

四、竞态条件和临界区

并发安全问题的产生源于多线程同时访问共享资源,且操作顺序敏感。

小故事:面包店的小明雇佣了两个助手小红和小绿做蛋糕。第三步"添加奶油和装饰"需要按顺序完成,但由于两人同时操作,导致蛋糕做砸了。

解决方案:引入规则——同时只有一人能操作最后一步。这个规则就是锁!

关键概念:

  • 临界区:共享资源或代码段,多线程同时访问会产生问题
  • 竞态条件:多个线程同时以不同顺序访问临界区
  • 锁:保证同一时刻只有一个线程能访问临界区

五、总结

线程是提升服务器资源利用率的关键工具。在本节中,我们学习了:

  • 线程的创建方式(Runnable、Callable)
  • 线程的参数(优先级、名称、守护线程)
  • 线程的停止方法(interrupt)
  • 线程的生命周期和状态
  • 并发安全问题的产生原因(竞态条件、临界区)

下一节,我们将学习如何合理、高效、安全地使用线程。

赞(0)
未经允许不得转载:网硕互联帮助中心 » 01 多线程初阶:解谜多线程世界
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!