透过现象看本质,一个Java多线程问题引出的思考

利用Solidworks2020将挖掘机装配体转换为URDF模型 利用Solidworks2020将挖掘机装配体转换为URDF模型一、下载sw_urdf_exporter插件 URDF(Universal Robot Description Format)——通用机器人描述格式,它是ROS里边使用的一种机器人的描述文件,包含的内容有:连杆、关节,运动学和动力学参数、可视化模型、碰撞检测模型等。 一、下载sw_urdf_exporter插件 ROS提供了SolidWorks转URDF的插件(下载链接)—sw2urdfSetup.exe,下载后点击安装,安装完成后就能在sol 阅读详情

读到这篇文章的朋友,请先看看下面的多线程场景下,程序的运行结果是什么? 如果你能准确的看到结果,那么请不要在这篇文章上浪费你的时间。程序很简单,主要有三个类。

类 ThreadTask : 主要通过execute方法执行Task的一个任务。这里定义的任务就是对int 型变量循环加一,直到大于或等于10为止。代码如下


public class ThreadTask {
	
	private int i = 0;  //定义ThreadTask类的一个私有变量
	
	public void execute(String threadName){
		System.out.println("Thread "+threadName+" start to execute.......");
		
		try {
			
			while(i<10){
				i++;
				System.out.println("Thread "+threadName+" increments to "+i);
				Thread.sleep(1000);
			}
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Thread "+threadName+" execute completes.......");
	}

}

类 ThreadWrapper : 很简单,就是定义一个线程类。执行时调用ThreadTask对象的execute方法。

public class ThreadWrapper implements Runnable {

	
	private String _threadName;
	private ThreadTask _t;
	
	public void run() {
		_t.execute(this._threadName);
	}
	
	public ThreadWrapper(String ThreadName,ThreadTask t){
	   this._threadName = ThreadName;
	   this._t = t;
	}

}

另外,有一个测试类TestStub如下,它生成4个线程,并分别执行这4个线程。所有四个线程共享一个ThreadTask实例。


public class TestStub {

	public static void main(String[] args){
		ThreadTask ts = new ThreadTask();
		for (int i =1;i<=4;i++){
			Thread t = new Thread(new ThreadWrapper("Thread" + i,ts)); //请注意,所有线程中传入的是一个ThreadTask实例。
			t.start();
		}
	}
}

那请问,上述代码执行时,各个线程之间在执行ThreadTask实例中的execute方法时是否会相互影响?私有变量i是否是线程安全的?

请看下面的执行结果示例

Thread Thread1 start to execute.......
Thread Thread1 increments to 1
Thread Thread3 start to execute.......
Thread Thread3 increments to 2
Thread Thread2 start to execute.......
Thread Thread2 increments to 3
Thread Thread4 start to execute.......
Thread Thread4 increments to 4
Thread Thread1 increments to 5
Thread Thread3 increments to 6
Thread Thread2 increments to 7
Thread Thread4 increments to 8
Thread Thread3 increments to 10
Thread Thread2 execute completes.......
Thread Thread1 increments to 10
Thread Thread4 execute completes.......
Thread Thread3 execute completes.......
Thread Thread1 execute completes.......

很明显,多个线程在同时执行ThreadTask的execute方法,同时在对私有变量i就行加法操作,他们相互影响了各自的行为。

那现在,我们来做一个简单的代码变更,将私有变量i从类ThreadTask的内部转移到其方法execute的内部。代码如下


public class ThreadTask {
	
	public void execute(String threadName){
		System.out.println("Thread "+threadName+" start to execute.......");
		int i = 0; //定义一个方法的内部局部变量i
		try {
			
			while(i<10){
				i++;
				System.out.println("Thread "+threadName+" increments to "+i);
				Thread.sleep(1000);
			}
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Thread "+threadName+" execute completes.......");
	}

}

这时,如果再运行TestStub类,那结果会是怎样?线程还会争抢这个变量i吗?变量i是否是线程安全的呢?答案是线程没有对这个变量产生竞争,变量i是线程安全的。请看下面的运行结果

Thread Thread1 start to execute.......
Thread Thread1 increments to 1
Thread Thread2 start to execute.......
Thread Thread2 increments to 1
Thread Thread3 start to execute.......
Thread Thread3 increments to 1
Thread Thread4 start to execute.......
Thread Thread4 increments to 1
Thread Thread2 increments to 2
Thread Thread3 increments to 2
Thread Thread1 increments to 2
Thread Thread4 increments to 2
Thread Thread3 increments to 3
Thread Thread1 increments to 3
Thread Thread2 increments to 3
Thread Thread4 increments to 3
Thread Thread2 increments to 4
Thread Thread3 increments to 4
Thread Thread1 increments to 4
Thread Thread4 increments to 4
Thread Thread3 increments to 5
Thread Thread1 increments to 5
Thread Thread4 increments to 5
Thread Thread2 increments to 5
Thread Thread3 increments to 6
Thread Thread4 increments to 6
Thread Thread1 increments to 6
Thread Thread2 increments to 6
Thread Thread3 increments to 7
Thread Thread2 increments to 7
Thread Thread4 increments to 7
Thread Thread1 increments to 7
Thread Thread2 increments to 8
Thread Thread1 increments to 8
Thread Thread3 increments to 8
Thread Thread4 increments to 8
Thread Thread2 increments to 9
Thread Thread1 increments to 9
Thread Thread3 increments to 9
Thread Thread4 increments to 9
Thread Thread2 increments to 10
Thread Thread1 increments to 10
Thread Thread3 increments to 10
Thread Thread4 increments to 10
Thread Thread3 execute completes.......
Thread Thread2 execute completes.......
Thread Thread4 execute completes.......
Thread Thread1 execute completes.......

如果上述两次的输出结果你都预见到了,你可以不必往下看了。否则,请和我一起往下看看为什么会是这样?多个线程既然可以争抢同一个实例中的一个私有变量,从而产生冲突,那为什么多个线程不去争抢同一个实例中的同一个方法的局部变量呢?

为了解释清楚这个问题,需要从Java虚拟机的结构说起,让我们看看下面的Java虚拟机的体系结构图



在这里,我不打算花篇幅介绍整个JVM的结构,因为他们很容易理解,Java 类装载器装载.class文件,由执行引擎运行。如果你知道Java可以调用系统的本地方法,那么本地方法接口和本地方法库也就是顺理成章的事情。我主要把精力放在了运行时数据区上,也就是中间那个大框里的小框框。我们知道,当Java虚拟机运行一个Java程序,它需要内存来存储诸如字节码,程序创建的对象,传递给方法的参数,返回值,局部变量等信息。这些信息就存储在了上图中的一个个运行时数据区中。

为了解释上述两个多线程实例(为了引用方便,就分别称呼为例一和例二吧)的行为,我们从线程共享的角度将这些运行时数据区分为两类。第一类包括,方法区 和堆,他们是由所有的Java 虚拟机线程所共享的。第二类包括PC 寄存器,Java 栈,和本地方法栈,他们是由每个Java虚拟机线程所私有的。

读到这里,你肯定已经明白为什么例一中定义的对象的私有变量会被多个线程争抢,这个对象的私有变量肯定是在第一类运行时数据区存储,那例二中方法内定义的局部变量肯定是在第二类运行时方法区中存放。事实也确实如此,那对于例一中类对象定义的内部变量到底是存在方法区中还是堆中呢?例二中方法内部的局部变量又是存在于哪个数据区呢?

接下来,让我们先看例一中涉及到的方法区和堆吧。


方法区中主要存放被Java虚拟机装载的类的如下类型信息

  • 这个类型的全限定名
  • 这个类型的直接超类的全限定名
  • 这个类型是类类型还是接口类型
  • 这个类型的访问修饰符,例如public,abstract,或final
  • 任何直接超接口的全限定名的有序列表
  • 该类型的常量池
  • 字段信息。字段的类型,和修饰符
  • 方法信息。方法名,返回类型,参数的数量和类型,方法修饰符
  • 一个到Class类的引用
  • 一个到ClassLoader的引用
  • ...........

在Java虚拟机规范中提到方法区在逻辑上是堆的一部分。虽然规范并没有强制定义方法区物理上一定要在堆上,但这也足以告诉我们方法区和堆之间有千丝万缕的联系。例如,Java 虚拟机总是可以通过在方法区的类型信息来确定一个对象创建时从堆上需要多少内存。


堆中存放的是Java虚拟机运行时创建的所有类实例或数组。Java虚拟机有在堆上分配新对象的指令,但没有释放内存的指令,这些都需要靠Java虚拟机实现的垃圾回收机制类处理。Java虚拟机规范中并没有规定堆上的对象的表示方式,这给Java虚拟机的实现者很大的自由。这里列出了几种可能的方式。第一种就是将堆分成两部分,一个句柄池,一个对象池。一个对象引用就是一个指向句柄池的本地指针。句柄池的每个条目有两部分,一个指向对象实例的指针,一个指向方法区类型数据的指针。如下图所示

还有一种是使对象指针直接指向一组数据,而该数据包括对象实例数据以及指向方法区中类数据的指针。如下图所示



除了上述两种对象表示形式外,在方法区的类数据表示上,Java虚拟机的实现者可以采用方法表的形式,将类型信息作为一个索引表进行存储,这样会加快查找,但在空间上会有些浪费。这里就不做过多的介绍。因为到此为止,我们已经很清楚的看到类对象的数据是存储在堆上的。另外,这里没有对数组在堆上的表示形式进行说明,数组中的数据也是存放在堆上。


从上面对堆和方法区的介绍,我们知道例一中对象的私有变量是存放在堆上,并被Java虚拟机中的多个线程所共享。所以,会出现例一的读写冲突结果。


接下来,我们看看例二中的方法内局部变量到底是来自哪里?

PC寄存器是在线程启动时创建,当线程执行某个Java方法时,如果这个方法不是本地方法,PC寄存器包含当前被执行的Java虚拟机指令的地址。如果当前执行的方法时本地方法,那么PC寄存器中的状态将会是"Undefined"。


Java 栈 (在最新的Java虚拟机规范中,它被称为Java虚拟机栈,我们这里还是称它为Java栈,叫起来比较方便),每当启动一个新线程,Java虚拟机会为它分配一个Java栈。Java栈上所有的数据都是线程私有的。任何线程都不能访问另一个线程的栈数据。Java 栈以帧为单位保存线程的运行状态。某个线程正在执行的方法称为线程的当前方法,当前方法使用的栈帧就叫当前帧。每当线程调用一个Java方法(非本地方法)时,虚拟机都会向该线程的Java栈中压入一个新帧。而这个新帧就是当前帧,在线程执行方法时,它使用这个帧来存储参数、局部变量、中间运算结果等数据。再进一步的话,每个栈帧是由局部变量区、操作数栈、和帧数据区组成。其中,局部变量区就是用来存储对应方法的参数和局部变量的。


说到这里,我们已经很清楚的知道,例二中类对象的方法中的局部变量就是保存在Java栈中的当前栈帧的局部变量区。不同的线程独立拥有这个空间,其他线程无法访问。所以,方法内局部变量没有发生多个线程冲突的情况。


至此,我们的问题基本已经解决了,但如果你需要再了解一些本地方法栈及其与Java栈,PC寄存器之间的联系,请继续往下看

本地方法栈,Java 虚拟机可以但不限于使用C栈来实现本地方法栈。如果一个Java虚拟机的具体实现根本不需要或不允许调用本地方法(这在规范上是允许的),那么,它就没有必要提供本地方法栈。一旦提供,那本地方法栈是由每个线程私有的。当Java虚拟机调用本地方法时,虚拟机不会往Java栈中压入新的栈帧,而是转而在本地方法栈中压入新的栈帧来表示当前调用的本地方法。


下图是一个虚拟机实例的快照,能进一步说明本地方法栈,PC寄存器,和Java栈之间的联系。有三个线程在运行,线程1和线程2都在执行Java方法,线程3在执行一个本地方法。



上图中,当前正在执行的方法在 Java栈和本地方法栈中以蓝色表示。对于一个正在运行的Java方法的线程,本例中的线程一和线程二而言,它的PC寄存器总是指向当前被执行的指令。由于线程三正在运行一个本地方法,因此,它的PC寄存器的状态为"undefined",用深色表示。






iqoo11如何获取root权限? 🏆本文收录于专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家!持续更新中,up!up!up!! 阅读详情

相关推荐

【QGIS】【OsGeo4w】安装方法

every blog every motto: You will never know unless you try 0. 前言 因为目前要使用QGIS,然而环境配置就整了大半天,哎,进行简单记录,方便自己方便他人。 一共分为两种方式安装: 独立安装包 网络安装包(下载osgeo4w-setup) QGIS提供了不同的版本: 长期发行版(LTR) 最新版(LR) 开发人员版本(DEV,母版或测试版) 说明: 本文推荐第二种 1. 正文 1.1 下载osgeo4w 下载链接 下载完成: 1.2

胡侃有料的博客 2万+

Java 多线程:多线程产生的原因

包括: 一. Java 内存模型 二. i ++ 操作的实质 三. Java 多线程产生的原因 四. 总结 一. Java 内存模型 线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM(Java内存模型)的一个抽象概念,并不真实存在。它

不更新了 2115

Linux系统下奥比中光Astra Pro相机SDK部署与避坑指南

本文详细指导了在Linux系统下部署奥比中光Astra Pro深度相机SDK的全过程,涵盖系统准备、SDK安装、设备权限配置及常见问题排查。重点解析了USB设备规则配置这一关键步骤,并提供了Python与C++项目的集成方法,旨在帮助开发者快速完成相机配置,避免常见陷阱。

weixin_28455801的博客 298

java异常本质论

(1)对java异常的本质是什么?   Java异常主要处理编译器不能捕获的错误,使得程序在运行时出现问题的情况下能够继续下去,而不导致程序终止,确保程序的健壮性。   处理过程:产生异常时,如果当前的context不具备处理当前异常的能力,将在heap上new一个异常对象,停止当前的执行线路,将产生的异常对象   抛给更上层的context。 (2)java异常的继承体系是?常见java

淡定老杨 614

802.1AS时间同步机制深度解析:从Sync报文到多域冗余设计

本文深度解析了802.1AS时间同步机制,从Sync与Follow_Up报文的核心交互原理入手,详细阐述了其如何通过精确的时钟频率比测量、链路延迟计算和驻留时间补偿来实现微秒乃至纳秒级同步。文章进一步探讨了802.1AS-2020版本引入的多时钟域冗余设计,为构建高可靠的车载TSN网络提供了关键见解和实战配置指南。

pytorch8learner的博客 457

STM32CubeIDE之SHT3X温湿度传感器移植HAL库

有了前面的OLED的学习,这个学习起来也很快。 分以下几步走 1.你要有个温度传感器,SHT3X这个型号的,因为我要讲这个 2.你要有个STM32开发板(我用的是STM32L431RCT) 3.顺便找台电脑下载一个STM32CubeIDE 4.简单的找一个SHT3X的驱动,我是去某宝嫖的,一般卖这个的都有,这个驱动分两个文件,是.c和.h的,我直接把这两个放在下边 读了我上一篇的人,看这个应该很熟悉吧,一样的套路,学习方法是一样的,你就照搬就行 下面是sht3x.c的原文档,里面有个CRC..

qq_47736089的博客 2313

好程序员的十大习惯之三 透过现象看本质,抓住最重要的事情

这段时间因为年底,忙了一点,但看到大家对十大习惯系列非常期待,所以我无论再晚,也得有时间来写。这次说的习惯,是一个思维习惯。我说过,我这个习惯系列,不是随便拿出一些生活中的习惯来告诉大家。每一个习惯都有非常深刻的意义。如果你看过《现在,发现你的优势》你就知道,很多人都有某些相对强烈的思维模式。这种思维模式,就可以称之为才干。它会向漏斗一样,过滤掉你的思维模式关注

韩小明@xiammy的专栏 5545

三分钟解决RKNN-Toolkit2安装失败:从模块报错到成功验证的完整记录

本文详细记录了RKNN-Toolkit2安装失败的解决方案,从环境配置到模型转换实战,特别针对常见的'No module named 'rknn''报错提供了完整修复指南。通过YOLOv8模型转换示例,展示了从ONNX到RKNN格式的完整流程,并分享了在RK3588芯片上的部署优化技巧。

html8的博客 264

透过现象看Java AIO的本质

透过现象看Java AIO的本质 ~~~

crg18438610577的博客 835

2.4G/4G天线共存方案:Air8101多频段隔离设计实战(附波长计算表)

本文深入探讨了物联网设备中Wi-Fi 2.4GHz与4G LTE天线共存设计的实战方案。针对B40与2.4G频段紧邻带来的干扰挑战,文章系统性地提出了空间隔离、PCB布局优化、结构设计三重防线,并提供了关键的波长计算工具与系统级验证Checklist,旨在帮助工程师将多频段隔离设计从“玄学”变为可执行的工程规范。

weixin_29197051的博客 388

使用R语言获取data.frame中指定列的数据

这里以"df"为例,包含三列数据:“列1”、“列2"和"列3”。通过以上代码,我们成功获取了"列1"和"列3"的数据,并将它们分别存储在了变量"column1"和"column3"中。假设我们有一个名为"df"的data.frame,其中包含了多个列,我们想要提取其中的某一列。符号,我们可以从data.frame中提取出"列2"的数据,并将其赋值给变量"column2"。符号,我们可以轻松提取出data.frame中特定列的数据,并将其存储在变量中供进一步的分析和处理使用。假设我们要获取"列2"的数据。

DevRevolt的博客 2321

透过现象看Java AIO的本质 | 得物技术

关于Java BIO、NIO、AIO的区别和原理,这样的文章非常的多的,但主要还是在BIO和NIO这两者之间讨论,而关于AIO这样的文章就少之又少了,很多只是介绍了一下概念和代码示例。在了解AIO时,有注意到以下几个现象:1、 2011年Java 7发布,里面增加了AIO称之为异步IO的编程模型,但已经过去了近12年,平时使用的开发框架中间件,还是以NIO为主,例如网络框架Netty、Mina,Web容器Tomcat、Undertow。

BASK2312的博客 611

16、树莓派Pico W:蓝牙与Wi-Fi应用指南

本文介绍了树莓派Pico W在蓝牙与Wi-Fi通信方面的应用,涵盖蓝牙配对原理、使用HC-06模块实现手机远程控制LED和传输内部温度,以及通过Wi-Fi进行网络连接、扫描和UDP协议下的设备控制。文章包含详细电路连接、代码实现与测试步骤,并提供拓展建议、常见问题解决方法及开发注意事项,帮助读者快速掌握基于Pico W的无线通信项目开发,适用于物联网入门与实践场景。

sun99的博客 289

到底什么是Java AIO?为什么Netty会移除AOI?一文搞懂AIO的本质!

Java AIO的这些不合常理的现象难免会令人心存疑惑。所以决定写这篇文章时,我不想只是简单的把AIO的概念再复述一遍,而是要透过现象,深入分析、思考和并理解Java AIO的本质。

hellojackjiang2011的博客 1277

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

JAVA多线程之基础(1)

前言: 写博客主要是记录平常所学习的知识,如有错误之处,还望指正...... 废话不多说,直接开始 附:(本文章主要讲解线程的实现方式和线程的停止/复位以及线程六种状态之间的转换) 在之前的面试中,我相信一定有小伙伴遇到面试官问实现线程有几种方式,大多数小伙伴都说的是两种,三种,四种,只有极少人会说一种,那么今天我们来说一下,实现线程的方式到底有几种? 先来说一下常见的几种线程实现方式 1.继承Thread类 2.实现 Runnable 接口 3.带返回值的Callable/Fut.

weixin_44516586的博客 189

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

java多线程nullpointerexception_多线程与高并发绕不开的ThreadLocal以及其GC友好设置...

前言在并发量较大的场景下,为了处理一个耗时的操作,大部分开发人员的解决办法就是使用多线程处理,从而提高处理效率,但是与此同时又会引出一个新的问题:如果线程其私有的数据需要存储,做其自定义的操作怎么办?这就引出了今天的主角:ThreadLocal。那他究竟是何方神圣呢?ThreadLocal是JDK1.2提供的一个工具,它为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出...

weixin_28881787的博客 509

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

深入ThreadLocal

ThreadLocal与线程成员变量还有区别,ThreadLocal该类提供了线程局部变量。这个局部变量与一般的成员变量不一样,ThreadLocal的变量在被多个线程使用时候,每个线程只能拿到该变量的一个副本,这是Java API中的描述,通过阅读API源码,发现并非副本,副本什么概念?克隆品? 或者是别的样子,太模糊。   准确的说,应该是ThreadLocal类型的变量内部的注册

gaokewoo的专栏 303

Java死锁深度解析:从面试官的角度理解并发编程中的“死胡同“

从面试官和面试者的对话展开,深入解析Java死锁的原理、检测、预防和解决方案,涵盖死锁的四个必要条件、经典案例、现代并发工具使用等核心知识点。

weixin_54726354的博客 307

Java中的明星类介绍-“String类“

导语:在写这篇文章时我是惴惴不安的 因为String的地位在Java中实在是太高了 Java面试也是必问类型之一 。一个是怕自己理解的不够透彻对读者产生一些误解 一个是关于String的东西实在是太多 我想10篇文章也不一定说的完 那基于这一点 我想我还是挑精华的东西讲 尽可能帮助Java新人理解String本质的东西 语言总是晦涩难懂的【不管是编程语言还是人类发明的自然语言 】 我更希望和喜欢透过现象看本质

qq_38012000的博客 441

走个心:在软件圈,破万“卷”的本质无疑就是返璞归真?

最近两年,整个软件行业,被内卷这个词汇所席卷,各位应当深有体会。 那么对于程序员来说什么才是内卷?是必备的面试八股文?是35岁危机?是996的加班文化?还是你渐渐稀疏的头发? 说起本质,作为技术人,还是基于对技术或能力的欠缺,下面我们来分析下原因,以及 为何会内卷? 简单来说,造成内卷的因素基本源于自身的原因。 自身学历和地位的原因。 自我认知的原因。 自我提升的能力。 就目前来说,自身的学历并没有很重要。不说大厂,在很多新兴互联网公司,独角兽企业,哪怕你是中专还是高中,仍然有...

wdjnb的博客 866

Java并发编程—实现线程的方式只有一种

对于很多Java工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些资料希望对Java开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。再分享一波我的Java面试真题+视频学习详解+技能进阶书籍试真题(都整理成文档,小部分截图)免费分享给大家,有需要的可以点击进入暗号:优快云!免费分享~记得关注我!对于很多Java工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。

2401_85111736的博客 962

劲爆!97道大厂Java核心面试题出炉,来试试看你会几道题

总的来说,面试是有套路的,一面基础,二面架构,三面个人。最后,小编这里收集整理了一些资料,其中包括面试题(含答案)、书籍、视频等。希望也能帮助想进大厂的朋友《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取![外链图片转存中…(img-OKmE5LKZ-1711903583733)]《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

2401_83703866的博客 1029

java php python 高并发_纯 Web 后端领域,Java,PHP,Python,Node.js 这四个哪个更有前途?...

后端领域现在非常细化,分布式、微服务等基础设施的成熟会将业务逻辑更大程度的独立出来。java/php/C# 目前仍是实现业务逻辑的最优选择。java/php 如果不是有特别的限制条件,比如必须用java或php生态的某些东西,看个人爱好选择一个方向,但需要注意几个方面javaservlet架构在现在有逐渐淘汰的趋势,tomcat、jetty也将逐渐完成他们的历史使命,把更多精力放在java本身,...

weixin_39608526的博客 278

太厉害了!2021年百度Java面试真题,2021最新版!

前言 今日博主听闻,现在很多培训出来的应届生薪资都赶上了摸爬滚打两三年的朋友,讲道理,这说不过去啊 作为同行来说,这个行业发展很快,技术更新很快,淘汰也很快,千万不要再找借口了,想吃这碗饭不如好好思考如何提升自己的技术,提高自己的核心竞争力。 下面博主给大家分享一波十月份精选的互联网大厂Java核心面试题,透过面试题来分析自己所掌握的技术栈与大厂所需的差距,判断面试难易程度,从而进一步明确自己学习的方向。 天下码农,多为CV!你是否每天还在增删改查?性能优化让你手足无措?看这里!技术大牛带你分分钟完爆性能优

m0_57501579的博客 226

java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程

java作为第一大编程语言,可谓源远流长,一代又一代的java程序员前仆后继走在java学习的路上。java程序员的学习之路在2020年又有什么变化呢?本文详细附上了每一个部分所需知识的教程链接地址,并会持续更新,希望能够和大家一起进步!

程序那些事 2万+

Java面试核心:从HashMap到Spring循环依赖的深度解析与实战指南

在Java技术体系中,理解核心数据结构的底层原理是构建扎实基础的起点。以HashMap为例,其从数组+链表到引入红黑树的演进,以及扩容机制与线程安全性的考量,深刻体现了数据结构设计如何平衡时间与空间效率,并直接影响高并发场景下的应用性能。同样,在主流框架如Spring中,对Bean生命周期和依赖注入机制的掌握,是保障应用稳定运行的关键。Spring通过三级缓存与早期暴露机制巧妙解决循环依赖问题,这一设计不仅展现了容器的核心管理能力,也关联着AOP代理等高级特性的实现。深入理解这些基础概念与实现原理,对于进行

weixin_31714129的博客 248
上一篇: Java中 Package Sealing 的探秘之旅
下一篇: 被动实例化 -- 性能与资源占用之间的平衡
TechNerd
博客等级 码龄14年 5粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值