读书笔记--Java与线程

并发不一定要依赖多线程(如PHP中很常见的多线程并发),但是Java里面谈论并发,大多数都与线程脱不了关系。

线程的实现

        我们都知道,线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件I/O等),又可以独立调度(线程是CPU调度的最基本单位)。

主流的操作系统都提供了线程的实现,Java语言则提供了在不同硬件和操作系统平台下对线程操作的统一处理,每个java.lang.Thread类的实例就代表一个线程。不过Thread类与发部分Java API有显著的差别,它的所有关键字方法都被声明为Native。在Java API中的一个Native方法可能就意味着这个方法没有使用或者无法使用平台无关的手段来实现(当然也有可能是为了执行效率而使用Native方法,不过通常最高效率的手段也就是平台相关的手段)正是这个原因,本节的标题才定为”线程的实现“而不是”Java线程的实现“。

        实现线程主要有三种方式:使用内核线程实现、使用用户线程实现、使用用户线程加轻量级进程混合实现。

          1、使用内核线程实现

        内核线程(Kernel Thread,KLT)就是直接由操作系统内核支持的线程,这种线程由内核来完成线程切换,内核通过操纵调度器对线程进行调度,并负责将线程的任务映射到各个处理器上。每个内核线程都可以看做是内核的一个分身,这样操作系统就有能力同时处理多件事情,支持多线程的内核就叫多线程内核。

        程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口--轻量级进程(Light Weight Process,LWP),轻量级进程就是我们通常意义上所讲的线程,由于每个轻量级进程都由一个内核线程支持,因此只有先支持内核的线程,才能有轻量级进程。这种轻量级进程与内核线程之间1:1的关系称为一对一的线程模型,如下图所示:

        由于内核线程的支持,每个轻量级进程都成为一个独立的调度单元,即使有一个轻量级进程在系统调用中阻塞了,也不会影响整个进程继续工作。但是轻量级进程具有它的局限性:首先,由于是基于内核线程实现的,所以各种进程操作,如创建、析构及同步都需要进行系统调用。而系统调用的代价相对较高,需要在用户态和内核态中来回切换。其次,每个轻量级进程都需要有一个内核线程的支持,因此轻量级进程要消耗一定的内核资源(如内核线程的栈空间),因此一个系统支持轻量级进程的数量是有限的。

           2、使用用户线程实现

        广义上讲,一个线程只要不是内核线程,那就可以认为是用户线程(User Thread, UT),因此从这个定义上来讲,轻量级进程也属于用户线程,但轻量级进程的实现始终是建立在内核之上的,许多操作都是要进行系统调用,因此效率会受到限制。

       而狭义上的用户线程指的是完全建立在用户空间的线程库上,系统内核不能感知到线程存在的实现。用户线程的建立、同步、销毁和调度完全在用户态中完成,不需要内核的帮助。如果程序实现得当,这种线程不需要切换到内核态,因此操作可以是非常快切低消耗的,也可以支持规模更大的线程数量,部分高性能数据库中的多线程就是由用户线程实现的。这种进程与用户线程之间1:N的关系称为一对多的线程模型,如下图所示:

        使用用户线程的优势在于不需要系统内核支援,劣势也在于没有系统内核的支援,所有的线程操作都需要用户程序自己处理。线程的创建、切换和调度都是需要考虑的问题,而且由于操作系统只把处理器资源分配到进程,那诸如阻塞如何处理,“多处理器系统中如何将线程映射到其他处理器上”这类问题解决起来将异常困难,甚至不可能完成。因而使用用户线程实现的程序一般都比较复杂,除了以前在不支持多线程的操作系统中的多线程程序与少数有特殊需求的程序外,现在使用用户线程的程序越来越少,Java、Ruby等语言都曾经使用过用户线程,最终又都放弃了它。

           3、混合实现

        线程除了依赖内核线程实现和完全用户程序自己实现外,还有一种将内核线程与用户线程一起使用的实现方式。在这种混合实现下,既存在用户线程,也存在轻量级进程。用户线程还是完全建立在用户空间中,因此用户线程的创建、切换、析构等操作依然廉价,并且可以支持大规模的用户线程并发。而操作系统提供支持的轻量级进程则作为用户线程与内核线程之间的桥梁,这样可以使用内核提供的线程调度功能及处理器映射,并且用户线程的系统调用要通过轻量级线程来完成,大大降低了进程被阻塞的风险。在这种混合模式中,用户线程与轻量级线程的数量比是不定的,是M:N的关系,如下图所示,这就是多对多的线程模型。

Java线程调度

        线程调度是指系统为线程分配处理器使用权的过程,主要调度方式有两种,分别是协同式(Cooperative Threads- Scheduling)线程调度和抢占式线程调度(Preemptive Threads- Scheduling)线程调度

        如果使用协同式调度的多线程系统,线程的执行时间由线程本身来控制,线程把自己的工作执行完了之后,要主动通知系统切换到另一个线程上去。协同式多线程的最大好处是实现简单,而且由于线程要把自己的事情干完后才会进行线程切换,切换操作对线程自己是可知的,所以没有什么线程同步的问题。Lua语言中的“协同例程”就是这类实现。它的坏处也很明显:线程执行时间不可控制,甚至如果一个线程编写有问题,一直不告诉系统畸形线程切换,那么程序就会一直阻塞在那里。很久以前的Windows 3.x系统就是使用协同式来实现多进程多任务的,那是相当的不稳定,一个进程坚持不让出CPU执行时间就会导致整个系统崩溃。

        虽然说Java线程调度是系统自动完成的,但是我们还是可以“建议”系统给某些线程分配多一些执行时间,另外的一些线程则可以少分配一点--这项操作可以通过设置线程优先级来完成。Java语言一共设置了10个级别的线程优先级(Thread.MIN_PRIORITY 至Thread.MAX_PRIORITY ),在两个线程同时处于Ready状态时,优先级越高的线程越容易被系统选择执行。

不过,线程优先级并不是太靠谱,原因是Java的线程是被映射到系统的原生线程上实现的,所以线程调度最终还是由操作系统说了算,虽然很多操作系统都提供线程优先级的概念,但是并不见得能与Java线程的优先级一一对应。如下所示的Java线程优先级与Windows线程优先级之间的对应关系:

        上文说到的“线程优先级并不太靠谱”,不仅仅是说一些平台上的不同的优先级实际会变得不同这一点,还有其他情况让我们不能太依赖优先级:优先级可能会被系统自行改变。例如Windows系统中存在一个名为“优先级推进器”的功能,它的大致作用就是当系统发现一个线程被执行的特别勤奋努力的话,可能会越过线程优先级去为它分配执行时间,因此我们不能在程序中通过优先级来完全准确判断一组状态都为Ready的线程将会执行哪一个。

状态切换

Java语言定义了5种进程状态,在任意一个时间点中,一个进程只能有且只有其中一种状态,这5种状态分别是:

  • 新建(New):创建后尚未启动的线程处于这种状态。
  • 运行(Runable):Runable包括了操作系统线程状态中Running和Ready,也就是处于此状态的线程由可能正在执行,也有可能在等待着CPU为它分配执行时间。
  • 无限期等待(Waiting):处于这种状态的进程不会被分配执行时间,它们要等待被其他线程显式地唤醒,在一定时间之后它们会由系统自动唤醒。以下方法会让线程进入无限期等待状态:
    • 没有设置Timeout参数的Object.wait() 方法
    • 没有设置Timeout参数的Thread.join( ) 方法
    • LockSupport.park() 方法
  • 限期等待(Timed Waiting):处于这种状态的进程不会被分配CPU执行时间,不过无需等待被其他线程显示地唤醒,在一定时间之后它们会由系统自动唤醒。以下方法会让线程进入限期等待:
    • Thread.sleep() 方法。
    • 设置了Timeout参数的Object.wait() 方法
    • 设置了Timeout参数的Thread.join()方法
    • LockSupport.parkNanos() 方法
    • LockSupport.parkUnit() 方法
  • 阻塞(Blocked):进程被阻塞了,“阻塞状态”与“等待状态”的区别是:“阻塞状态”在等待着获取到一个排他锁,这个事件将在另外一个线程放弃这个锁的时候发生;而“等待状态”则是在等待一段时间,或者唤醒动作的发生。在程序等待进入同步区域的时候,线程将进入这种状态。
  • 结束(Terminated):已终止线程的线程状态,线程已经结束执行。

状态之间的转换关系如下图所示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/913442.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PICO+Unity 用手柄点击UI界面

如果UI要跟随头显,可将Canvas放置到XR Origin->Camera Offset->Main Camera下 1.Canvas添加TrackedDeviceGraphicRaycaster组件 2.EventSystem移动默认的Standard Input Module,添加XRUIInputModule组件 3.(可选)设置射线可…

三十六、Python基础语法(JSON操作)

JSON(JavaScript Object Notation)是一种基于文本,轻量级的数据交换格式。它易于人阅读和编写,同时也易于机器解析和生成,在自动化测试中经常用来存放测试数据。 JSON的特点: 基于文本,不包含图…

产品设计理念:10个案例分享

在互联网时代,企业通过在线产品为用户提供服务。要在众多竞争产品中脱颖而出并吸引更多用户,企业不仅要提供优质的服务,还要在产品设计上给用户带来卓越的体验。互联网产品设计包括页面布局、服务内容、流程逻辑、色彩搭配、图标、按钮等多个…

智能社区服务小程序+ssm

智能社区服务小程序 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了智能社区服务小程序的开发全过程。通过分析智能社区服务小程序管理的不足,创建了一个计算机管理智能社区服务小程序的方案。文…

Flutter3.22.2中SliverAppBar设置背景色滑动显示颜色错误

在使用Flutter项目开发中,可能会有页面需要滑动收起标题栏的效果,一般都会使用SliverAppBar来实现,当项目的Flutter的SDK版本升级到3.4后,发现使用了SliverAppBar的页面,在滑动过程中,标题栏和状态栏的颜色…

Odoo | 免费开源ERP:汽车及零配件行业信息化解决方案

文 / 开源智造 Odoo亚太金牌服务 概述 围绕汽车行业产业链上下游企业的整体业务主线,提供面向汽车主机厂整车个性化制造解决方案,产业链上下游一体化协同解决方案,数字化精益制造解决方案、全价值链质量管理解决方案,数字化运营解…

目前对于后期的打算

在完成了 Python 基本语法的学习后,我犹如推开了编程世界的一扇大门,初窥门径却也深知前方还有广袤无垠的知识天地等待我去探索。Python 作为一门广泛应用于软件开发、数据分析和人工智能等领域的高级编程语言,在当今数字化时代具有举足轻重的…

React中右击出现自定弹窗

前言 在react中点击右键,完成阻止浏览器的默认行为,完成自定义的悬浮框(Menu菜单). 版本 "react": "^18.2.0", "umijs/route-utils": "^4.0.1", "antd": "^5.18.1", "ant-design/pro-components": &q…

Elasticsearch如果集群出现节点故障,我应该如何快速定位问题?

当 Elasticsearch (ES) 集群发生故障时,快速定位问题源头非常重要。Elasticsearch 是一个分布式系统,故障可能由多种原因引起,涉及到硬件、配置、网络、集群本身的健康状况等多个层面。以下是一些定位问题的步骤和工具: 检查集群…

【Docker】Docker基础及docker-compose

一、Docker下载 更新yum包 yum update 安装需要的软件包( yum-util 提供yum-config-manager功能,后两个是devicemapper驱动依赖) yum install -y yum-utils device-mapper-persistent-data lvm2 设置stable镜像仓库(使用阿里…

Linux:理解动静态库

一、前言 如果我们写了一些方法想给别人用??有什么办法呢?? ——>(1)我直接把头文件和源文件给他(.c.h) ——>这样会让别人轻易看到你的实现 (2)把源文件打包成库&#xff…

快速了解SpringBoot 统一功能处理

拦截器 什么是拦截器: 拦截器是Spring框架提供的重要功能之一,主要进行拦截用户请求,在指定方法前后,根据业务需求,执行预先设定的代码。 也就是说,允许开发⼈员提前预定义⼀些逻辑,在⽤⼾的请求响应前后执⾏.也可以…

随着最新的补丁更新,Windows 再次变得容易受到攻击

SafeBreach专家Alon Leviev发布了一款名为 Windows Downdate的工具,可用于对Windows 10、Windows 11 和 Windows Server 版本进行降级攻击。 这种攻击允许利用已经修补的漏洞,因为操作系统再次容易受到旧错误的影响。 Windows Downdate 是一个开源Pyth…

Linux笔记-对Linux环境变量的进一步认识(2024-08-09)

此篇公开到互联网上的时间是:2024-11-11 主要是PATH和LD_LIBRARY_PATH。 基本概念 在 Linux 中,PATH 和 LD_LIBRARY_PATH 是两个不同的环境变量,它们的作用和使用场景有所不同。 PATH 作用:用来指定可执行文件的搜索路径。当你…

Linux操作系统之DHCP服务部署与配置

一、实验目的 1、理解DHCP的定义和工作原理; 2、掌握DHCP服务器的配置方法。 二、实验环境 1台PC、VMware虚拟机、3个CentOS7操作系统 三、实验步骤及内容 1、使用yum安装dhcp; 图1 安装DHCP服务 图2 查看DHCP是否安装 2、修改VM中虚拟网络编辑器…

优化时钟网络之时钟抖动

Note:文章内容以Xilinx 7系列FPGA进行讲解 1、什么是时钟抖动 时钟抖动就是时钟周期之间出现的偏差。比如一个时钟周期为10ns的时钟,理想情况下,其上升沿会出现在0ns,10ns,20ns时刻,假设某个上升沿出现的时…

第三十六章 Vue之路由重定向/404页面设置/路径模式设置

目录 一、路由重定向 1.1. 使用方式 1.2. 完整代码 1.2.1. main.js 1.2.2. App.vue 1.2.3. index.js 1.2.4. Search.vue 1.2.5. Home.vue 1.3. 运行效果 二、设定404错误页面 2.1. 使用方式 2.2. 完整代码 2.2.1. index.js 2.2.2. NotFound.vue 2.2.3. 运行效…

PostgreSQL的奥秘:深入探究事务与锁的秘密世界

PostgreSQL事务 1. 概述 在数据库系统中,事务(Transaction)是执行数据库操作的最小逻辑单位。它确保了一组操作的完整性和一致性。事务可以通过显式的 BEGIN、COMMIT 和 ROLLBACK 语句块来控制,也可以在自动提交模式&#xff08…

Three.js 搭建3D隧道监测

Three.js 搭建3D隧道监测 Three.js 基础元素场景scene相机carema网络模型Mesh光源light渲染器renderer控制器controls 实现3d隧道监测基础实现道路实现隧道实现多个摄像头点击模型进行属性操作实现点击模型发光效果 性能监视器stats引入使用 总结完整代码 我们将通过three.js技…

netstat中sendq/recvq用于排查发送端发送数据的问题

web同事开发了一个用于接收syslog数据的服务器,不清楚web的开发方式,用来联调的发送端是我们的C模块 反馈syslog udp形式接收正常,速度正常,数量也正常,syslog tcp形式接收开始比较快后面越来越慢,并且知道…