java

java并发-线程

4.1线程简介

4.1.1什么是线程

现代操作系统在运行一个程序时,会为其创建一个进程。例如,启动一个Java程序,操作 系统就会创建一个Java进程。现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight Process),在一个进程里可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局 部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换,让使用者感觉 到这些线程在同时执行。

一个Java程序的运行不仅仅是main()方法的运行,而是main线程和多个其他线 程的同时运行,如

  • Signal Dispatcher:分发处理发送给JVM信号的线程,
  • Finalizer: 调用对象finzzilze方法的线程
  • Reference Handler: 清除Reference的线程

4.1.2 为什么要使用多线程

  • (1)更多的处理器核心

  • (2)更快的响应时间 有时我们会编写一些较为复杂的代码(这里的复杂不是说复杂的算法,而是复杂的业务逻 辑),例如,一笔订单的创建,它包括插入订单数据、生成订单快照、发送邮件通知卖家和记录 货品销售数量等。用户从单击“订购”按钮开始,就要等待这些操作全部完成才能看到订购成 功的结果。但是这么多业务操作,如何能够让其更快地完成呢?

在上面的场景中,可以使用多线程技术,即将数据一致性不强的操作派发给其他线程处 理(也可以使用消息队列),如生成订单快照、发送邮件等。这样做的好处是响应用户请求的线 程能够尽可能快地处理完成,缩短了响应时间,提升了用户体验。

  • (3)更好的编程模型

Java为多线程编程提供了良好、考究并且一致的编程模型,使开发人员能够更加专注于问 题的解决,即为所遇到的问题建立合适的模型,而不是绞尽脑汁地考虑如何将其多线程化。一 旦开发人员建立好了模型,稍做修改总是能够方便地映射到Java提供的多线程编程模型上。

4.1.3 线程优先级

现代操作系统基本采用时分的形式调度运行的线程,操作系统会分出一个个时间片,线 程会分配到若干时间片,当线程的时间片用完了就会发生线程调度,并等待着下次分配。线程 分配到的时间片多少也就决定了线程使用处理器资源的多少,而线程优先级就是决定线程需 要多或者少分配一些处理器资源的线程属性。

在Java线程中,通过一个整型成员变量priority来控制优先级,优先级的范围从1~10,在线 程构建的时候可以通过setPriority(int)方法来修改优先级,默认优先级是5,优先级高的线程分 配时间片的数量要多于优先级低的线程。设置线程优先级时,针对频繁阻塞(休眠或者I/O操 作)的线程需要设置较高优先级,而偏重计算(需要较多CPU时间或者偏运算)的线程则设置较 低的优先级,确保处理器不会被独占。在不同的JVM以及操作系统上,线程规划会存在差异, 有些操作系统甚至会忽略对线程优先级的设定。

4.1.4 线程的状态

状态名称说明
NEW初始状态,线程被构建,但是还没有调用start()方法
RUNNABLE运行状态(对应操作系统的就绪和运行)
BLOCKED阻塞状态
WAITING等待状态,表示线程进入等待状态,进入该状态表示当前线程需要等待其他线程做出一些特定的动作(通知或中断)
TIME_WAITING超时等待状态,该状态不同于WAITING,它是可以在指定的时间自行返回的
TERMINATED终止状态,表示当前线程已经执行完毕

image

4.1.5 Daemon线程

Daemon线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。这 意味着,当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出。可以通过调 用Thread.setDaemon(true)将线程设置为Daemon线程。

注意 Daemon属性需要在启动线程之前设置,不能在启动线程之后设置。

注意 在构建Daemon线程时,不能依靠finally块中的内容来确保执行关闭或清理资源的逻辑。

关于作者

程序员,软件工程师,java, golang, rust, c, python,vue, Springboot, mybatis, mysql,elasticsearch, docker, maven, gcc, linux, ubuntu, centos, axum,llm, paddlepaddle, onlyoffice,minio,银河麒麟,中科方德,rpm