当前位置: 首页 > news >正文

单核CPU是否有线程可见性问题?

本文仅是本人对问题的思考记录,并没有实操验证,有误请大家评论指出。

今天见到了一个经典的问题,单核CPU是否有线程可见性问题,学完操作系统应该可以直接回答,不会有线程安全问题。但如果结合JVM虚拟机来进行分析,就又麻烦了一点。结合线程切换和JVM内存区域,本文重新梳理了一下对这个问题的思考。

文中可能还有其他问题,例如JDK8之后就没有方法区的概念了,

以及最后的data=1只是为了表示对数据进行更改,没有考虑变量存储位置和引用类型等问题。

1 从JVM内存区域说起

我们都知道,JVM的内存区域有两部分,一部分是线程共享的:堆和方法区(JDK8之后变为元空间的概念,且位于本地内存中),另一部分是线程私有的:虚拟机栈、本地方法栈、程序计数器。

请添加图片描述

既然是线程私有的,那么如果有多线程,难道有多个虚拟机栈、本地方法栈、程序计数器吗?答案是否定的。一个JVM虚拟机的内存区域就是这样的。那么问题来了,一个线程占有了这三个私有区,那其他线程到哪去了?我们需要回顾操作系统中的线程和进程间的关系:

线程和进程的关系

王道书里是这么解释的:进程是一个独立的运行单位,也是操作系统进行资源分配的基本单位。而线程不拥有资源,但却是CPU调度的最小单位。

进程。它包含三个部分:PCB(Process Control Block)进程控制块、程序段、数据段。其中PCB为核心,该结构常驻内存,与进程同生共死。切换进程的时候,处理机状态信息必须保存到响应的PCB中,以便在该进程重新执行时,能从断点继续执行。

线程。除了有TCB(Thread Control Block)线程控制块之外,还有其专有的存储区。切换线程的时候,状态信息需要保存到TCB中。

这里插入思考一个问题,为什么线程切换比进程切换更轻量级?

回答这个问题,我们首先要知道“保存状态信息”到底保存了什么?由于一个进程用到的数据都会加载到内存中(可能只加载了一部分,通过虚拟内存),所以PCB中保存的都是一些地址引用,而不是数据实体。大概包括:

  • 进程描述信息:PID、UID
  • 进程控制和管理信息:进程状态、优先级、代码入口地址、CPU占用时间、程序的外存地址等
  • 资源分配清单:I/O设备信息、代码段指针、数据段指针、堆栈指针、文件描述符等
  • CPU相关信息:各种寄存器的值、状态字

即便是只需要保存地址引用,但仍然需要保存这么多的信息。而线程切换时,TCB需要保存的,相比之下就轻量级很多:

  • PC程序计数器(寄存器)、栈等信息。

这两个一对比,就发现了切换的代价,线程切换明显更轻。

线程与进程在Android中的表现
一个Java程序,通过main()开启了它的进程生涯,承载这个程序的,就是JVM虚拟机。可以理解为,JVM虚拟机就是这个java程序的进程的概念。

Android的进程是什么呢?在Zygote孵化器 fork() 进程的时候,我们发现它还fork()了虚拟机,准备好虚拟机后,反射执行了ActivityThread的main()方法,换句话说,Android中一样也是一个虚拟机对应了一个APP进程。

APP进程中可能有很多线程,比如binder线程、用户自己开辟的线程。这些线程的切换,都通过TCB来进行现场的保存与恢复。虚拟机栈、本地方法栈、程序计数器在内存中的地址信息都会通过TCB来进行保存和恢复。

我们还要注意到,TCB和PCB的保存与恢复类似,都是保存数据地址,例如栈信息的数据地址、寄存器的数据等。线程的栈中有局部变量表,它通过指针,JVM中线程共享的部分获取数据,它本身并不存储数据。线程私有的,是线程各自的局部变量表、程序计数器等信息,而并不是数据本身。例如下面这张图所示的虚拟机栈内部结构,都是一些指针信息,并没有保存数据本体。

img

到这里,我们来梳理一下:

  1. App进程的切换,本质上是对该进程的PCB(程序控制器)的信息进行保存与恢复。其信息具体指向的内容,仍然还在内存中。
  2. 线程的切换,如果是同一进程下的线程切换,本质上是对线程的TCB(线程控制器)的信息进行保存与恢复。其信息具体指向的内容,仍然在对应进程所拥有的内存空间中。

我们来看到下面这张图:

请添加图片描述

为了结构清晰,这里没有加入多级Cache缓存,主要为了表达,如果仅是线程切换,只需要切换TCB的信息即可,也就是从上图蓝线引用切换为粉线引用,而PCB的信息则不需要改动。当然,如果要切换其他进程,就需要对PCB进行保存和恢复了。

到这,我们最初的问题:“一个JVM虚拟机的内存区域就是这样的,一个线程占有了虚拟机栈、本地方法栈、程序计数器,那其他线程到哪去了?”。可以回答,其他线程的虚拟机栈、本地方法栈、程序计数器还在内存中,这三者在内存中的地址信息存在了TCB(线程控制块)中。当这个线程需要被调度的时候,通过TCB的地址信息,将这个线程的数据恢复回来。

Java的线程是如何实现的?

我们从启动线程的源码中也能看到,start()最终调用到start0()这个本地方法,这就说明Java线程的启动是由JVM底层来决定的。又提到王道操作系统的内容,我们知道线程分为:用户线程、核心线程、组合线程。Java线程的实现方式随不同操作系统而异。

在《深入理解JVM虚拟机》中说到,例如Windows和Linux中,都是使用一对一的线程模型来实现的,一条Java线程对应一条轻量级进程。在Unix平台中,可以支持一对一以及多对多。但都没有使用用户线程,主要原因是,如果使用用户线程,进程就要自己处理线程的创建 、切换和销毁,但最重要的麻烦在于,很难处理:“阻塞如何处理”、“多处理器时,如何将线程映射到其他处理器上并行执行”。

下图给出用户线程与轻量级进程1:1的关系,其中UT为用户线程(User Thread)同时也是Java线程,LWP为轻量级进程(LowWeight Process),KLT为内核线程(Kernel-Level Thread):

请添加图片描述
也正是有内核线程的参与,即由操作系统介入,把线程作为最小单位进行调度,才使得在多核CPU下,一个Java进程的多个线程,可以运行在不同的处理机上。

2. 多核CPU的结构图

铺垫了这么多,仍然不能切入主题,在讨论线程间可见性问题的时候,避不开缓存一致性问题。我们知道,ALU计算单元的处理速度远高于内存数据的读写速度,所以我们引入了多级缓存,来减小这种效率差。为了节省时间,我们直接考虑一个JVM虚拟机进程,在多级缓存中是如何表现的,且我只画了二级缓存:

请添加图片描述

主存的数据很多,缓存中只根据局部性原理留下了几个物理块。我们先来梳理几个概念,再进入线程间可见性问题。

首先,JVM内存区域中的堆和方法区的“共享”概念,在上面这张图中就体现了。不同的线程并行跑在不同的CPU中,访问的都是JVM内存区域中的“共享”区。但是,由于多级缓存,Java线程访问到的只是一份数据拷贝,并不是真正对主存的数据做处理。我们首先明确一点,缓存中的数据是真拷贝,缓存是从主存中拷贝了一整个物理块到缓存中来,而不是保存了指向主存的指针。

在不同CPU中对共享区域数据的修改,在使用“写回法”的情况下,只要没出现物理块的调换,就不会将更改后的数据更新回主存。其他线程也根本不知道这部分数据被改了:

请添加图片描述

这久发生了线程安全问题,到底应该听谁的呢?最后写回主存的时候就会无法确认最后的data到底是2还是3。

Java中通过volatile、final、synchronized关键字来实现线程间可见性

为了解决这种缓存一致性问题,java引入了volatile、final、synchronized关键字来实现线程间可见性问题。具体如何做到的,这里就不做多余分析了。通过线程间可见性关键字,让对变量的访问需要强制从内存中重新把数据刷回。

3. 最后回到正题,单核CPU会有线程可见性问题么?

答案是没有的。还是刚才的例子,现在只有CPU-1,首先来到线程A,将data从1改为2:

请添加图片描述

接下来,进行线程切换,线程私有区被切换为了线程B的内容,但共有部分并不需要切换,这是进程资源,只有在进程切换,或者缺页等情况发生的时候,才会有所变动。

轮到线程B执行,线程B也要访问data变量,通过局部变量表的指针,找到了位于堆中data的位置,

请添加图片描述

由于线程B访问的也是这一块缓存,即便是没有缓存一致性协议,它仍然能够访问到最新的值,因为这里根本就不存在同一级别的缓存出现不一致的情况,因为它最终层级只有一个缓存。至此,就搞通了为什么单核CPU下的多线程场景,不会造成线程安全,不会有线程可见性问题。

当然,在进行进程切换时,或者发生缓存缺页时,进程的物理块可能会被逐层写回主存,但这并不影响我们之前的分析。

此外,本文举的data例子是int变量,暂且认为是一个对象中的某个成员变量,所以修改的是堆中某个对象的成员变量的值,避免掺杂其他问题。

单核CPU还有必要开启多线程吗?
还是有必要的,举个例子,其中一个线程需要进行I/O操作,不希望在IO还没完成的时候把CPU时间交给它,浪费CPU资源。

4. 参考文献

《深入理解Java虚拟机》,周志明

《王道操作系统考研复习指导》,王道论坛

相关文章:

单核CPU是否有线程可见性问题?

本文仅是本人对问题的思考记录,并没有实操验证,有误请大家评论指出。 今天见到了一个经典的问题,单核CPU是否有线程可见性问题,学完操作系统应该可以直接回答,不会有线程安全问题。但如果结合JVM虚拟机来进行分析&…...

MyBatis 架构介绍

MyBatis 架构介绍MyBatis 架构图MyBatis 所解决的 JDBC 中存在的问题引用MyBatis 架构图 mybatis 配置:mybatis-config.xml,此文件作为 mybatis 的全局配置文件,配置了 mybatis 的运行环境等信息。另一个 mapper.xml 文件即 sql 映射文件,文件…...

加密算法---RSA 非对称加密原理及使用

加密算法---RSA 非对称加密原理及使用一 非对称加密原理介绍二 加密解密测试2.1 加密解密工具类2.2 测试一 非对称加密原理介绍 非对称加密算法中,有两个密钥:公钥和私钥。它们是一对,如果用公钥进行加密,只有用对应的私钥才能解…...

MySQL-查询语句

数据库管理系统的一个最重要的功能就是数据查询,数据查询不应只是简单查询数据库中存储的数据,还应该根据需要对数据进行筛选,以及确定数据以什么样的格式显示。MySQL提供了功能强大、灵活的语句来实现这些操作。下面是通过help帮助查看到的s…...

【算法】【数组与矩阵模块】求数组中需要排序的最短子数组长度

目录前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本思考感悟写在最后前言 当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识! 问题介绍 …...

centos安装Anaconda3

目录一、参考二、Anaconda简介1、用途2、关于anaconda三、下载安装1、下载2、安装anaconda3、配置环境遍历4、测试配置结果5、设置显示前缀一、参考 在centos上安装Anaconda 最新Anaconda3的安装配置及使用教程(附图文) 二、Anaconda简介 一句话&…...

【微信小程序】-- WXML 模板语法 - 列表渲染 -- wx:for wx:key(十二)

💌 所属专栏:【微信小程序开发教程】 😀 作  者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…...

【Linux】Linux中gcc/g++的使用

本期主题:程序的编译过程和gcc/g的使用博客主页:小峰同学分享小编的在Linux中学习到的知识和遇到的问题小编的能力有限,出现错误希望大家不吝赐🍁 1.背景知识 预处理(进行宏替换,去注释,头文件的…...

【Spring Cloud Alibaba】(五)Dubbo启动报错?一直重连报错?你值得学习的是排查问题的方法

系列目录 【Spring Cloud Alibaba】(一)微服务介绍 及 Nacos注册中心实战 【Spring Cloud Alibaba】(二)微服务调用组件Feign原理实战 【Spring Cloud Alibaba】(三)OpenFeign扩展点实战 源码详解 【Spri…...

adb命令的使用

命令 连接机顶盒 adb connect [机顶盒ip]查看已连接设备 adb devices断开某个机顶盒的连接 adb disconnect [机顶盒ip] or adb disconnect [虚拟机名称]断开所有设备连接 adb disconnect获取 root 权限 adb root挂载文件系统 adb remount当想往移动设备端 push 文件时显…...

springBoot自定义参数类型转换器

springBoot允许用户自定义转换器,以处理自定义请求参数协议。 方式一:通过实现接口:WebMvcConfigurer 并重写方法的形式。 Configuration public class BootConfig implements WebMvcConfigurer {/*** 自定义参数转换*/Overridepublic voi…...

OA系统在企业中的应用你知道哪些?

随着人工智能技术的不断发展,企业中的OA系统(Office Automation System)正在逐渐得到广泛应用。OA系统是一种集成了多种功能的信息化工具,能够帮助企业实现办公自动化、信息管理、决策支持等多种功能。本文将从OA系统在企业中的应…...

JAVA中,ArrayList 的扩容机制,含案例

JAVA中,ArrayList 的扩容机制,含案例 在 Java 中,ArrayList 是一个动态数组,它可以根据需要自动增长。当 ArrayList 中的元素数量超过其初始容量时,它会重新分配一个更大的内部数组,然后将现有元素复制到新…...

供应链的有效管理,分析指标有哪些

对于企业而言,供应链是一个很复杂的、体系化的生态系统,从原材料、到供应商、到生产、仓库、物流,最后到达经销商或者最终客户那里,这个链条很长。相关的分析指标也有很多,在这些指标里面也有非常多可以扩展、延申的内…...

嵌入式环境配置—VMware 软件安装和虚拟机的创建

目录 一、VMware软件的安装 二、虚拟机的创建 三、Linux操作系统的安装 VMware软件的安装 为什么要虚拟机? 嵌入式Linux开发需要在Linux系统下进行,我们选择了Ubuntu。 1.双系统安装 有问题,一次只能使用一个系统。Ubuntu基本只做编译用。需求&…...

阿里前端二面经典手写面试题汇总

实现类的继承 实现类的继承-简版 类的继承在几年前是重点内容,有n种继承方式各有优劣,es6普及后越来越不重要,那么多种写法有点『回字有四样写法』的意思,如果还想深入理解的去看红宝书即可,我们目前只实现一种最理想…...

【Eye】Fake News Reading on Social Media: An Eye-tracking Study

Fake News Reading on Social Media: An Eye-tracking Study Abstract 在网上传播假新闻(以及一般的虚假信息)最近被认为是威胁整个社会的一个主要问题。这种传播在很大程度上是由于新的媒体形式,即社交网络和在线媒体网站。研究人员和从业…...

想学计算机,应该学什么专业?

我们在考虑想学计算机,应该学什么专业?这个问题的时候,每个人都应该结合自己的兴趣来确定。有的喜欢编程、有的喜欢设计、有的喜欢做产品跟人打交道……自己有兴趣再加上自己的努力,掌握好专业技能,就一定能进入高薪的…...

Android逆向之旅—反编译利器Apktool使用教程

apktool下载软件首先下载apktool.bat和apktool.jar官网地址:https://ibotpeaches.github.io/Apktool/install/配置环境变量具体的apktool命令自行百度apktool 解包与打包解包: apktool d xxx.apk打包: apktool b xxx1.jadx安装与使用下载exe或…...

色环电阻的阻值如何识别

这种是色环电阻,其外表有一圈圈不同颜色的色环,现在在一些电器和电源电路中还有使用。下面的两种色环电阻它颜色还不一样,一个蓝色,一个土黄色,其实这个蓝色的属于金属膜色环电阻,外表涂的是一层金属膜&…...

Dataway 让 Spring Boot 不再需要 Controller、Service、DAO、Mapper 简单接口直接开发。

新的sql语法可以先看一下官网&#xff0c;部署起来之后会用到Dataql&#xff1a; DataQL - 数据查询语言https://www.dataql.net/先看一下效果 接下来来实现一下。 1 创建spring boot项目 导入依赖 <!--begin dataWay--><!--hasor-spring 负责 Spring 和 Hasor 框架之…...

C#窗口介绍

窗口就是打开程序我们所面对的一个面板&#xff0c;里面可以添加各种控件&#xff0c;如下图所示&#xff0c;我们可以在属性栏设置其标题名称、图标、大小等。图1 窗口图 图2 设置面板 图3 设置双击标题框&#xff0c;会生成Load函数&#xff0c;也可以到事件里面去找Load函数…...

SpringBoot:SpringBoot整合Junit 和 MyBatis(3)

SpringBoot整合Junit 和 MyBatis1. SpringBoot整合Junit2. SpringBoot整合MyBatis2.1 定义SpringBoot项目2.2 定义dao接口2.3 定义service层2.4 定义controller层2.5 配置yml/yaml文件2.6 postman测试1. SpringBoot整合Junit 在com.example.service下创建BookService接口 publ…...

Web自动化测试框架Selenium

作者&#xff1a;霍格沃兹测试开发学社 链接&#xff1a;https://www.zhihu.com/question/59854292/answer/2827875817 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 什么是自动化测试 自动化测试就是&#xff0…...

大数据系统自检

第一章 大数据计算系统概述 1.1 大数据计算框架概述 Hadoop Hadoop的运行过程&#xff08;5个步骤&#xff1f;&#xff09; split > map > shuffle > reduce > output Hadoop的详细运行过程&#xff1f;&#xff08;4个大过程&#xff0c;6662&#xff09; 创建…...

MySQL数据库操作

查看数据库语法show databases——列出所有的数据库 show databases [ like wild ];——列出和字符串wild名字相同的数据库 这里可以配合SQl的 "%" 和 "_" 通配符使用来查找多个数据库在SQL语句中"%"代表任意字符出现任意次数,"_"代表…...

线程安全实例分析

一、变量的线程安全分析 成员变量和静态变量是否线程安全&#xff1f; ● 如果它们没有共享&#xff0c;则线程安全 ● 如果它们被共享了&#xff0c;根据它们的状态是否能够改变&#xff0c;又分两种情况 —— 如果只有读操作&#xff0c;则线程安全 —— 如果有读写操作&am…...

Tomcat源码分析-启动分析(二) Catalina初始化

Bootstrap Tomcat运行是通过Bootstrap的main方法&#xff0c;在开发工具中&#xff0c;我们只需要运行Bootstrap的main方法&#xff0c;便可以启动tomcat进行代码调试和分析。Bootstrap是tomcat的入口&#xff0c;它会完成初始化ClassLoader&#xff0c;实例化Catalina以及loa…...

基础复习第二十二天 泛型的使用

泛型JDK1.5设计了泛型的概念。泛型即为“类型参数”&#xff0c;这个类型参数在声明它的类、接口或方法中&#xff0c;代表未知的通用的类型。例如&#xff1a;java.lang.Comparable接口和java.util.Comparator接口&#xff0c;是用于对象比较大小的规范接口&#xff0c;这两个…...

【C++进阶】三、二叉搜索树

目录 一、二叉搜索树 1.1 概念 1.2 二叉搜索树操作 二、二叉搜索树实现 2.1 框架总览 2.2 实现接口总览 2.2.1 构造函数 2.2.2 拷贝构造 2.2.3 赋值重载 2.2.4 析构函数 2.2.5 二叉搜索树的遍历 2.2.6 插入函数 2.2.7 查找函数 2.2.8 删除函数 2.3 二叉搜索数完整…...

个人网站论坛展示/seo攻略

本文转载自&#xff1a;数据库精讲SQL优化——优化必备的 EXPLAIN 命令索引优化 一、优化必备的 EXPLAIN 命令 EXPLAIN 是用来查询 SQL 的执行计划&#xff0c; 用法&#xff1a; EXPLAIN SELECT [字段...] FROM TABLE;结果&#xff1a; -----------------------------------…...

b2c网站管理/网站seo是干什么的

前言 跳槽&#xff0c;这在 IT 互联网圈是非常普遍的&#xff0c;也是让自己升职加薪&#xff0c;走上人生巅峰的重要方式。那么作为一个普通的Android程序猿&#xff0c;我们如何才能斩获大厂offer 呢&#xff1f; 疫情向好、面试在即&#xff0c;还在迷茫踌躇中的后浪们&…...

长春病毒最新消息/seo顾问合同

我希望通过这种有关Leadership Lessons&#xff08;领导者课程&#xff09;的博客计划传递的一个主要价值是&#xff0c;揭示今天各阶层的大多数天才专业人士经常遇到的‘C-Level and Exec Myth’。那些达到管理和首席级别的人们都是具有非凡的激情、精力和激励能力的普通人而已…...

高唐建筑公司网站/百度网站排名怎么提高

工作需要经常在web目录下上传文件,都是小文件,几k~几十k,专门开一个ftp服务器或者用nfs共享都略显麻烦.偶尔看到一款小工具lrzsz 觉得挺好用.特标注!!!废话少说,开始上图.1/不想看详情的可以用yum -y install lrzsz2/创建一个文件测试下3/设置CRT的上传下载目录4/语法: sz x 下…...

wordpress主题是用什么开发出来的/sem竞价推广代运营收费

设置方法 选中贴图 在属性面板&#xff0c;拖动Aniso Level的值从0~9改变&#xff0c;值越大贴图越清晰&#xff0c;但是消耗也变大&#xff0c;文档说会造成显卡消耗&#xff0c;一般只用在地面上&#xff0c;其他地方没必要 遇到的问题 但是打包到Ipod上面&#xff0c;如果只…...

菏泽做网站多少钱/属于网络营销的特点是

Tomcat版本问题&#xff0c;servlet乱码问题 我在学习的时候&#xff0c;老师用的是Tomcat1.7版本&#xff0c;在jsp发送get请求的时候&#xff0c;Servlet中还要对get请求传递过来的参数进行解码编码&#xff0c;因为tomcat1.7版本之前的内部编码为ISO8859-1&#xff0c;然而在…...