从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 新闻合订本
    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 新闻合订本
    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

    • 反射

    • 注解

    • 集合类

    • 线程

      • 进程和线程的基本概念
      • Java 中的线程
        • 主线程
        • Java 中的线程
        • 创建线程方式之一
        • 多线程内存图解
      • Thread 类的方法
      • Runnable 接口
      • 匿名内部类方式实现线程的创建
      • 线程安全问题
      • 线程状态
      • 等待唤醒机制
      • 线程池
  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java
  • JavaSenior
  • 线程
2024-01-26
目录

Java 中的线程

# Java 中的线程

接下来我们实操下,在 Java 中创建线程

# 主线程

先来说一个比较特殊的线程:主线程。

主线程是执行主方法(main)的线程。我们之前写的 Java 程序中只有一个线程,也叫单线程程序,执行从 main 方法开始(由 JVM 执行),从上到下依次执行,main 方法会进入到栈内存

JVM 会找操作系统开辟一条 main 方法通向 CPU 的执行路径,CPU 就可以通过这个路径来执行 main 方法,而这个路径有一个名字,叫 main(主)线程

我们新建一个 Person 类,有 name 属性,setter/getter,构造方法和 run 方法:

package chapter200Thread;

public class Person {
    private String name;

    public void run(){
        // 定义循环,执行20次
        for (int i = 0; i < 20; i++) {
            System.out.println(name + " --> " + i);
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
  
    public Person() {

    }

    public Person(String name) {
        this.name = name;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

然后我们新建一个类用这个 Person:

package chapter200Thread;

public class Demo01MainThread {
    public static void main(String[] args) {
        Person p1 = new Person("小强");
        p1.run();

        Person p2 = new Person("旺财");
        p2.run();
    }
}
1
2
3
4
5
6
7
8
9
10
11

执行结果:各执行了 20 次循环。

缺陷:如果中途有异常,则后续的代码不能执行,例如我们加个异常:

package chapter200Thread;

public class Demo01MainThread {
    public static void main(String[] args) {
        Person p1 = new Person("小强");
        p1.run();
  
        int i = 0 / 0;
        Person p2 = new Person("旺财");
        p2.run();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

运行结果:

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at chapter200Thread.Demo01MainThread.main(Demo01MainThread.java:8)
1
2

我们可以创建两个线程,一个线程输出“小强”,一个线程输出“旺财”,这样即使有一个线程异常了,也不会影响另一个。

# Java 中的线程

Java 使用 java.lang.Thread 类代表线程,所有的线程对象都必须是 Thread 类或其子类的实例。

我们可以看官网文档 (opens new window)中,对 Thread 类的说明:

A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.

线程是程序中的执行线程,JVM 运行应用程序并发地运行多个执行线程。

Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon. When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon.

每个线程有个优先级,高优先级线程,会优先执行。每个线程都可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程是守护线程

....

There are two ways to create a new thread of execution. One is to declare a class to be a subclass of Thread. This subclass should override the run method of class Thread. An instance of the subclass can then be allocated and started. For example, a thread that computes primes larger than a stated value could be written as follows:

有两种方法创建线程,一种是将类声明为 Thread 的子类,该子类需重写 run 方法。接下来就可以分配并创建该子类的实例,例如,计算大于某一规定值的质数的线程可以写成:

class PrimeThread extends Thread {
         long minPrime;
         PrimeThread(long minPrime) {
             this.minPrime = minPrime;
         }

         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }
1
2
3
4
5
6
7
8
9
10
11

The following code would then create a thread and start it running:

然后,下列代码会创建并启动一个线程:

     PrimeThread p = new PrimeThread(143);
     p.start();
1
2

The other way to create a thread is to declare a class that implements the Runnable interface. That class then implements the run method. An instance of the class can then be allocated, passed as an argument when creating Thread, and started. The same example in this other style looks like the following:

创建线程的第二种方式是声明实现 Runnable 接口的类,然后实现 run 方法。然后就可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。采用这种方式的一个例子:


     class PrimeRun implements Runnable {
         long minPrime;
         PrimeRun(long minPrime) {
             this.minPrime = minPrime;
         }

         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }
 
1
2
3
4
5
6
7
8
9
10
11
12

The following code would then create a thread and start it running:

然后,下列代码会创建并启动一个线程:

     PrimeRun p = new PrimeRun(143);
     new Thread(p).start();
1
2

看完文档后,我们来实现下。

# 创建线程方式之一

我们先用第一种方式:创建 Thread 类的子类

实现步骤:

  1. 创建一个 Thread 类的子类
  2. 在 Thread 类的子类中重写 Thread 类中的 run 方法,设置线程任务
  3. 创建 Thread 类的子类对象
  4. 调用 Thread 类中的方法 start 方法,该方法会开启新的线程,并执行 run 方法

关于 start 方法的文档说明 (opens new window):

public void start()

Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread. The result is that two threads are running concurrently: the current thread (which returns from the call to the start method) and the other thread (which executes its run method).

It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.

使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

结果是两个线程并发地运行;当前线程(main 线程)和另一个线程(创建的新线程,会执行其 run 方法)。

多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。

Java 程序属于抢占式调度,哪个线程的优先级高,就会优先执行;同一个优先级,则随机选择一个执行。

我们创建一个类:

package chapter200Thread;

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++){
            System.out.println("run: " + i);
        }
    }
}
1
2
3
4
5
6
7
8
9
10

开启多线程:

package chapter200Thread;

public class Demo02ThreadSubclass {
    public static void main(String[] args) {
        MyThread t = new MyThread();
        t.start(); // 启动线程
        // 主线程继续执行
        for (int i = 0; i < 20; i++) {
            System.out.println("main: " + i);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

然后我们执行 main 方法,结果:

main: 0
run: 0
main: 1
run: 1
main: 2
run: 2
main: 3
run: 3
main: 4
main: 5
main: 6
run: 4
........
1
2
3
4
5
6
7
8
9
10
11
12
13

可以看到是交替输出的,也就是两个线程是交替执行的。

# 多线程内存图解

首先,我们写了 2 个方法:main 方法和 run 方法

当我们执行 main 方法的时候,会将 main 方法加载到内存中,我们可以称之为栈:

然后我们会创建 MyThread 对象,该对象会在内存中一个叫“堆”的地方,并且该对象有自己的内存地址:

然后当我们执行 run 方法的时候,如果是普通方法,此时就是单线程程序,该方法也会压栈执行,先执行 run 方法,再执行 main 方法后面的代码:

而我们是多线程,所以,当我们调用 start 方法的时候,会创建一个栈空间,所以我们的 run 方法是在新的栈空间执行:

同理,如果我们创建多个 MyThread 类,并且调用 start 方法,就会创建多个栈空间,并执行 run 方法,CPU 就会通过调度的方式,并发执行多个线程:

多线程的好处:多个线程互不影响,因为它们在不同的栈空间。

(完)

上次更新: 2025/6/3 09:31:54
进程和线程的基本概念
Thread 类的方法

← 进程和线程的基本概念 Thread 类的方法→

最近更新
01
新闻合订本 2025-10
10-31
02
2025 年 10 月记
10-30
03
用 AI 批量优化思源笔记排版
10-15
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式