线程的起源
线程的起源与计算机的发展历程密切相关。在计算机发展的早期阶段,系统采用了单指令模式,即一次只能执行一条指令,这种模式资源利用效率非常低下。随着计算机技术的进步,批处理模式(即计算机的多指令模式)应运而生,它允许计算机同时执行多条指令,从而有效提高了资源利用率。然而,这种模式也存在一个缺陷,即 CPU 经常会陷入等待状态,无法得到充分利用。为了解决这一问题,进程 (process) 的概念被引入。

进程
是指计算机执行一个程序时,系统为其分配的一段内存空间,用于存储程序的指令、数据和运行状态等信息。当用户向计算机发出一系列操作指令时,每个进程会将不同的操作储存起来,并随时进行切换。但是,进程的指令执行效率仍然不够快,无法在同一时刻执行多个任务。
为了进一步提高计算机的运行效率,技术人员发明了线程 (thread) 的概念。线程是进程中的单个执行流,它是 CPU 调度和分派的基本单位。有了线程以后,每个操作指令对应的任务都能够被划分为多个子任务,由每一个单独的线程负责执行。不同的线程可以同时运行,从而充分利用 CPU 的多核优势,大大提高了计算机的运行效率。线程的引入标志着计算机技术向并行计算的方向发展,为现代计算机系统的高性能奠定了基础。
线程在其生命周期中的六种状态

NEW 新建
在 Java 中,当一个新的线程对象被创建时,它会进入 NEW 新建状态。这是线程生命周期的初始状态。在这个状态下,线程对象已经被创建并分配了必要的资源,但还没有开始执行。当系统或软件运行时,会发出 start 指令创建线程实例,但是线程创建后并不一定会立即进入运行状态,它可能会暂时处于 NEW 新建状态,等待系统或程序为其分配 CPU 时间片。这种情况通常出现在系统或程序处于待机状态时。

Runnable 可运行
当线程对象从 NEW 新建状态进入 Runnable 可运行状态时,它已经准备好了执行线程中的任务。在这个状态下,线程可能正在运行代码,也可能仍处于等待 CPU 时间片的状态。这取决于操作系统处理器此时的工作状态和线程调度算法。Java 虚拟机是软件运行时产生的"工作间",它负责管理和调度线程的执行。一旦线程获得了 CPU 时间片,它就会开始执行线程中的代码。如果 CPU 时间片用完或被其他更高优先级的线程抢占,该线程会暂时从 Runnable 可运行状态退出,等待下一次获得 CPU 时间片。

Blocked 锁阻塞
在 Java 中,线程需要获取对象锁才能访问共享资源。当一个线程试图获取某个对象锁时,如果该对象锁正在被另一个线程占用,那么该线程将进入 Blocked 锁阻塞的状态。在这种状态下,线程将被阻塞,无法继续执行,直到它获取到所需的对象锁。当另一个线程占用完毕并释放对象锁时,锁阻塞的线程会从 Blocked 状态变为 Runnable 可运行的状态,等待获取 CPU 时间片继续执行。对象锁是 Java 中实现线程同步的关键机制,它可以确保共享资源在任何给定时间只被一个线程访问,从而避免了竞态条件和数据不一致的问题。

Waiting 无限等待
Waiting 无限等待状态是线程生命周期中的一种特殊状态。当一个线程进入这个状态时,它将一直等待直到另一个线程执行唤醒指令将其唤醒。进入 Waiting 状态后的线程是无法自动唤醒的,必须等待另一个线程调用 notify ( ) 或 notifyAll ( ) 方法才能够被唤醒。Waiting 无限等待状态一般发生在主线程异常退出或子线程没有按既定程序关闭的情况下。在这种情况下,子线程可能会一直处于 Waiting 状态,导致程序无法正常退出。因此,在编写多线程程序时,需要特别注意线程的正确关闭和同步机制,以避免出现死锁或无限等待的情况。

Timed Waiting 计时等待
Timed Waiting 计时等待状态出现在多线程同时运行的情况中。当多个线程同时运行时,由于对象锁的数量有限,无法满足所有线程同时获取对象锁并执行运行指令。因此,部分线程会进入 Timed Waiting 计时等待的状态,等待一段指定的时间后再次尝试获取对象锁。在这个状态下,线程会暂时释放所占用的资源,等待一段时间后再次尝试获取所需的对象锁。如果在指定时间内获取到对象锁,线程将从 Timed Waiting 状态转换为 Runnable 可运行状态,继续执行任务。否则,线程可能会重新进入 Timed Waiting 状态或执行其他操作。Timed Waiting 状态可以有效避免线程无限期地等待对象锁,从而提高程序的响应性和效率。

Terminated 被终止
Terminated 被终止状态是线程生命周期的最终状态。当系统关闭或程序结束工作时,运行过程中产生的各种线程也会随之停止工作和运行,进入到 Terminated 被终止的状态。这种状态下的线程已经不再存在于任何的系统或程序中,它们已经完成了分配的任务或被强制终止。线程进入 Terminated 状态后,将释放所有占用的系统资源,如内存、CPU 时间片等。需要注意的是,Terminated 状态并不意味着线程对象会被立即销毁,线程对象可能会继续存在一段时间,直到垃圾回收器将其回收。因此,在编写多线程程序时,应该确保所有线程都能正常终止,避免出现线程泄漏或资源占用的问题。
线程的应用场景
单独的一个线程并无实际应用场景,而多个线程的应用场景则非常广泛。以下是多线程最常见的应用场景:
服务器应用
- Web 服务器、游戏服务器等专用服务器广泛使用多线程技术
- 服务器的后台任务处理、异步处理和分布式计算等操作均通过多线程来实现
- 多线程可以提高服务器的并发处理能力和响应速度
批量操作
- 向多个用户批量发送电子邮件、发微博、记录日志等用户对软件的操作
- 通过多线程并行执行这些任务可以大幅提高效率
系统级应用
- 操作系统、数据库管理系统等系统级软件都广泛使用多线程技术
- 多线程可以提高系统的并发处理能力和资源利用率
图形界面应用
- 图形界面应用程序通常需要同时执行多个任务
- 使用多线程可以避免界面冻结和无响应的情况
综上所述,多线程的出现大大提升了计算机的操作效率,目前主流的软件开发都是基于多线程技术。多线程使得应用程序能够同时执行多个任务,提高了系统的并发性能和响应能力。
线程与进程的区别
线程和进程是操作系统中两个非常重要的概念,它们之间存在着明显的区别。

基本定义
进程是计算机中已运行程序的实例,是系统资源分配和调度的基本单位。每个进程都有自己独立的地址空间、内存资源和执行上下文。而线程是进程中的一个执行序列,是 CPU 调度和分派的基本单位。一个进程可以包含多个线程,这些线程共享同一进程的内存和资源。

资源占用
进程之间相互独立,拥有独立的内存地址空间,因此进程的创建和切换开销较大。而同一进程内的线程共享内存和资源,线程的创建和切换开销较小。一般来说,线程比进程更加"轻量级"。

并发性
进程是并发执行的基本单位,不同进程之间通过进程间通信机制进行通信。而线程是并发执行的更小单位,同一进程内的多个线程可以直接读写相同的内存区域,从而实现更高效的通信和协作。

调度方式
进程的调度是由操作系统内核完成的,而线程可以由内核调度,也可以由线程库在用户空间进行调度,从而提高系统的响应能力。
线程同步的重要性
线程同步对于多线程应用程序至关重要,旨在避免竞态条件和其他难以预料的行为。当多个线程同时访问共享资源时,如果没有适当的同步机制,可能会导致意外的数据更新和难以重现的错误。为了防止这些问题,线程 API 提供了互斥锁、条件变量和信号量等同步原语,用于锁定数据结构并控制并发访问。然而,如果锁粒度过细,这些同步机制也可能影响多处理器系统的性能。因此,在编写高效的多线程程序时,仔细设计和优化同步机制至关重要。
如何创建和管理线程
创建线程
在大多数编程语言中,创建线程的方式是通过调用线程库或操作系统提供的线程创建函数。这些函数通常需要传入一个函数指针作为线程的入口点,线程将从该入口点开始执行。一旦线程创建成功,它将与主线程并行运行。
线程调度
操作系统内核负责对线程进行调度,决定在任何给定时间运行哪些线程。大多数现代操作系统采用抢占式调度策略,即内核可以在任何时候暂停一个线程的执行,切换到另一个线程。这种调度策略可以确保所有线程都能获得公平的执行机会。
线程优缺点
线程的优点是可以提高程序的响应能力和并行处理能力,但同时也带来了一些挑战,如线程安全、死锁、活锁等问题。因此,在使用线程时需要格外小心,合理利用同步原语,避免出现并发问题。
线程同步
由于线程共享同一个进程的内存空间,因此在访问共享资源时很容易出现竞争条件和数据不一致的问题。为了避免这些问题,编程语言和操作系统通常提供了一些同步原语,如互斥锁、信号量、条件变量等,用于协调线程之间的执行顺序和对共享资源的访问。
线程池
为了避免频繁创建和销毁线程带来的开销,许多应用程序采用线程池的方式来管理线程。线程池中维护着一定数量的线程,当有新任务到来时,线程池会从空闲线程中选择一个来执行该任务。当任务完成后,线程不会被销毁,而是返回到线程池中等待下一个任务。
线程池的作用及优势

提高响应能力
线程池能够让应用程序保持对输入的响应能力,因为长时间运行的任务可以被分配给工作线程,而主执行线程仍然保持响应状态。这样可以避免应用程序在执行耗时任务时出现卡顿或无响应的情况,从而提高用户体验。

优化系统资源利用率
与单线程应用相比,使用多线程的应用程序能够更好地利用大量 CPU 核心资源。线程池通过重复利用预先创建的线程,避免了频繁创建和销毁线程的开销,从而提高了系统资源的利用效率。

控制并发数量
线程池允许开发人员控制并发线程的数量,从而避免过度消耗系统资源。通过设置合理的线程池大小,可以在并发性能和资源占用之间达到平衡,确保应用程序的稳定性和可扩展性。

实现并行处理
线程池允许应用程序将数据和任务分解为并行的子任务,这些子任务可以在多核或多 CPU 系统上并发执行。通过并行处理,线程池可以充分利用硬件资源,加快程序执行速度,提高整体性能。

简化线程管理
线程池将线程管理工作交给了库或操作系统,从而简化了应用程序开发人员的工作。开发人员无需关注线程创建、调度和销毁等底层细节,只需专注于业务逻辑的实现,从而提高了开发效率。
欢迎加入亚马逊云科技培训中心
欢迎加入亚马逊云科技培训中心
-
快速上手训练营
-
账单设置与查看
-
动手实操
-
快速上手训练营
-
第一课:亚马逊云科技简介
本课程帮助您初步了解云平台与本地环境的差异,以及亚马逊云科技平台的基础设施和部分核心服务,包括亚马逊云科技平台上的弹性高可用架构,架构设计准则和本地架构迁移上云的基本知识。
亚马逊云科技技术讲师:李锦鸿第二课:存储与数据库服务
您将在本课程中学习到亚马逊云科技上的三个存储服务分别是什么。我们也将在这个模块中为您介绍亚马逊云科技上的关系型数据库服务 Amazon Relational Database Service (RDS)。
亚马逊云科技资深技术讲师:周一川第三课:安全、身份和访问管理
在这个模块,您将学习到保护您在亚马逊云科技上构建的应用的安全相关知识,责任共担模型以及身份和访问管理服务, Identity and Access Management (IAM) 。同时,通过讲师演示,您将学会如何授权给 EC2 实例,允许其访问 S3 上的资源。
亚马逊云科技技术讲师:马仲凯 -
账单设置与查看
-
-
动手实操
-
快速注册账号 享用免费套餐
跟随注册步骤详解,三分钟快速创建账号,领取免费权益
打开中国区账号注册页面
01 填写您 注册账号的邮箱,点击“继续”
02 查看您的 注册账号邮箱
注: 发件箱 no-reply@register.signin.amazonaws.com.cn
03 输入 邮箱中收到的验证码,点击“继续”
注: 该链接中的内容显示语言是与您的网页浏览器设置相一致的,您可以根据需要自行调整语言栏。

填写用户名密码
.04e59cc081d6b1b4de2e80dca972273ad0cd7ace.jpg)
填写账号联系人以及公司信息
01 填写公司联系人 姓名全称
02 填写公司联系人的 联系电话
03 填写 公司名称
注: 公司名称请务必与您所提供的营业执照公司名称保持一致
04 填写 公司办公地址
注: 省份/自治区/直辖市 - 城市 - 区 - 街道门牌号以及楼层信息 - 邮政编码
05 请选择 是否需要发票
注: *附件-申请发票流程 供您参考
06 点击查看 客户协议 勾选方框表示您已阅读,并同意客户协议的条款
.dcb511571e7913a6581f0ae803797a01c918ac61.jpg)
企业信息验证
01 在此上传 企业注册执照
02 请填写网络安全负责人的 姓名
注: 该字段务必与您下方提供的身份证号匹配或与证件上的姓名保持一致
03 请填写网络安全负责人的 联系方式
注: 有效的电子邮件地址 - 有效的中国内地 手机号码 - 座机号码(如无座机,请填写正确有效的手机号码)
04 在此上传网络安全负责人的 身份证件
注: 当您选择证件类型为“身份证”时,您需要填写正确的身份证号码,选择其他证件类型时,您需要上传证件扫描稿
.8252245bf937985f0b90aaa376899e8932e71a49.jpg)
手机验证与支持计划
.7122fd576282aebfbd9ed8927a918a378c59550d.jpg)