自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

彩虹地带

程序员学习过程中的思考总结

  • 博客(44)
  • 资源 (4)
  • 收藏
  • 关注

原创 开篇语

其实自己一直对写文字是很有兴趣的,也曾经在上大学的时候,坚持写过一阵子的博客,但后来上班之后,由于自己的懒惰,渐渐的荒废掉了这一习惯。产生想自己写博客这一想法,其实很简单。一篇篇记录自己心路历程的文章,会在时间过去许久之后,当你再次把它们拿在手中的时候,发生的种种情景,历历在目,那种感觉是多么的美妙!想起小的时候,我们也会在家长睡觉之后,在一盏台灯下,偷偷写下属于自己的文字,那里面有我们年少时的秘

2012-07-03 18:56:09 903

原创 类变量、成员变量、局部变量分别存储在内存的什么地方?

修饰符修饰的变量,随着类的实例产生和销毁,是类实例的一部分由于是实例的一部分,在类初始化的时候,从运行时常量池取出直接引用或者值,与初始化的对象。在所在方法被调用时放入虚拟机栈的栈帧中,方法执行结束后从虚拟机栈中弹出。修饰符修饰,定义在方法外的变量,随着。局部变量是定义在类的方法中的变量,之前把静态变量存放于方法区,在。成员变量是定义在类中,但是没有。

2025-04-15 09:15:02 108

原创 JVM 的主要组成部分及其作用?

的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine。文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class。)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area。将源代码编译成字节码文件,字节码文件的后缀名为。)的方法区内, 而字节码文件只是 JVM。其实可以一句话来解释:类的加载指的是将类的。),将字节码翻译成底层系统指令,再交由。

2025-03-10 23:41:43 366

原创 Spring事务核心流程分析

到这里,我们的 获取事务 接口完成了 数据库连接的创建 和 关闭自动提交(开启事务),将。处理提交,先处理保存点,然后处理新事务,如果不是新事务不会真正提交,要等外层是新事务的。如果是新事务的话,进行数据清除,线程的私有资源解绑,重置连接自动提交,隔离级别,是否只。此方法做清除连接相关操作,比如重置自动提交啊,只读属性啊,解绑数据源啊,释放连接啊,清。线程的私有资源解绑,重置连接自动提交,隔离级别,是否只读,释放。和线程的私有资源解绑,重置连接自动提交,隔离级别,是否只读,

2025-02-28 14:06:11 605

原创 面试官在问Spring是如何实现事务的,你这样回答

创作内容丰富的干货文章很费心力,感谢点过此文章的读者,点一个关注鼓励一下作者,激励他分享更多的精彩好文,谢谢大家!

2025-02-27 15:51:49 332

原创 详解:事务注解 @Transactional

,另外,配置类事务的传播行为支持当前事务,当前如果没有事务,那么会创建一个事。事务的传播规则是指在多个事务方法相互调用的情况下,事务应该如何进行传播和管理。属性用于指定事务的传播行为,它决定了当前方法执行时,如何处理已经存在的事务。属性用于指定事务的隔离级别,它决定了当前事务与其他事务之间的隔离程度。事务的创建也是有一定的规则,对于一个方法里已经存在的事务,支持当前事务,如果当前没有事务,就以非事务来执行。以非事务执行操作,如果当前存在事务,则当前事务挂。新建事务,如果当前存在事务,就把当前事务挂起。

2025-02-26 15:43:17 610

原创 大厂面试题:读过Spring源码吗?说说Spring事务是怎么实现的?

事务必须是一个原子的操作序列单元,事务中包含的各项操作在一次执行过程中,要么全部执行成功,要么全部不执行,任何一项失败,整个事务回滚,只有全部都执行成功,整个事务才算成功。即不同的事务并发操纵相同的数据时,每个事务都有各自完整的数据空间,即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能相互干扰。指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不。数据库的默认隔离级别。在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其他事务干扰。

2025-02-25 15:00:30 490

原创 Spring Bean 初始化如何保证线程安全

已经被正确初始化了。并且这里的初始化不仅仅指构造函数中的内容,而是 Spring 语境下的初始化,还包括setter 注入,PostConstruct 初始化等。在 Spring Bean 的初始化中,我们通常不需要显式地指定某个字段是 volatile,是因为 Spring 有相关机制做了保证。于是,我们只要注入了某个 Bean,那么这个 Bean 的初始化的内容就是可见的,上例中,在。我们知道 Spring 默认创建的 Bean 是单例的,那么 Bean 中的字段需要声明成。的习惯,那是在作死吗?

2024-11-28 21:50:57 827

原创 良好的并发编程习惯之利用线程安全类

也因此,常见的并发需求通常也集中在对集合(collection)类的读写上。日常的线程安全问题通常会落在原始( primitive)类型和集合(Collection)类,而使用对应的线程安全类通常就能直接解决问题。我们日常开发中的并发需求,通常用 JUC 中的类替换相应的原始类型或集合类,就可以达到线程安全。两种同步原语,在性能要求高的一些场景下,用它们来实现细粒度的同步会极大增加代码的复杂程度,性能也不好。虽然可能显而易见,要注意的是只有包装类提供的方法才保证是原子的,而里面存储的内容则没有。

2024-11-28 21:43:38 1241

原创 良好的并发编程习惯之不可变(Immutability)

不可变对象在 Java 中主要需要解决的是“可见性”和“有序性”的问题,要保证线程看到对象时,对象已经是正确初始化的,而约定上的不可变并没有这个保证。理论上真正的不可变对象,还要求对象创建后其中的状态就不再修改,如果对象不提供任何修改内部状态的手段,我们就能百分百确定对象发布后是线程安全的。不可变对象的状态在构造函数中就唯一确定了,之后不接受任何的更改,因此编译器能对它做更可靠的优化,更容易保证它的线程安全性。当然没问题,这就是“约定” vs “机制”的问题了,约定技术上是可能被打破的,机制不会但代价高。

2024-11-27 23:30:06 935

原创 良好的并发编程习惯之封闭(Confinement)

例如有个 volatile 变量,在编写代码的时候,隐含实现了这样的约定:只有一个线程会“写”该变量,其它线程只会“读”操作。"Ad-hoc" 一般指“特别的、专门的、临时的”等,在编程的语境中一般指“具体情况具体分析”。要注意的是,由于需要为每个线程创建一个副本,如果初始化的代价比较高且经常性地创建新的线程,可能会有潜在的性能问题,虽然通常情况下不会成为问题。一般如果一个方法只依赖它的输入参数和方法内创建的局部变量,不依赖其它的全局的信息,则可以说这个方法是“无状态”的。的语义上就是“线程封闭”的。

2024-11-27 23:28:21 597

原创 常见线程安全问题之复合操作

通常原子类(如 AtomicReference) 对单个操作的原子性保证很方便,但复合操作本身需要加锁,这里再使用原子类就显得没必要了。从 TOCTOU 一节中我们知道,要解决这种竞争问题,需要把对状态的检查与使用都变成原子的,最简单的方式就是在方法上用。代码块保证原子性,在 ② 中用同样方法保证赋值的原子性。不过在本节我们要强调的是,即使每个操作本身是原子的,复合操作也不是原子的,这种情形有时候比较难一眼就认出来。都是原子的,只不过复合操作的问题是,即使每个操作都是原子的,操作整体也不是原子的。

2024-11-26 23:48:39 879

原创 常见线程安全问题之Double Checked Locking

最简单的解决方式是读操作也加锁,如果性能达不到要求,也可以像本节一样使用 volatile,但我个人不建议这么用,因为有太多细节需要考虑,可以使用 JUC 中的。问题不仅仅在于写的一方,即使 helper 被正确初始化并赋值,由于另一个线程所在的 CPU 可能会从缓存中读取 helper 的值,如果 helper 的新值还没有被更新到缓存中,则读取的值可能还是。因为 64 位的操作不是原子的,于是可能造成前后 32 位不是一起写入内存的,而另一个线程只读取先写入的 32 位,读到的结果不正确。

2024-11-26 23:43:28 920 2

原创 常见线程安全问题之TOCTOU

我们可以看到,TOCTOU 的主要问题在于状态的检查和状态的使用整体上不是原子的,而前面的章节中我们知道 Java 中最简单的实现原子性的方式是使用内置锁(intrinsic lock),即。TOCTOU 问题的根源是使用状态时,其实依赖了之前的状态检查结果,而在检查到使用的这段时间里,状态被其它线程/进程修改了,于是依赖的条件被打破,使得对状态的使用不再正确。是互斥锁,意味着即使初始化正确完成后,依然只有一个线程能执行代码,于是在高并发下性能不好,之后的章节中会介绍如何优化。Java 里最方便的是。

2024-11-25 13:47:45 800

原创 Happens Before

其它获取锁的线程会被阻塞,直到该锁被释放。本章中我们了解了只有“共享可变状态”的情形下,多线程间的先后顺序才会引发线程安全问题,之后列出了 Java 中的跨线程操作,最后学习了 Happens Before 的(非正式)的规则,以及 HB 规则如何帮助我们对程序运行结果做出推论。在执行时,会先拿到上锁对象的引用,然后尝试对该对象的监视器执行 lock 操作,得到锁后开始执行代码块里的操作,代码块执行结束后(不管是正常结束还是抛异常),会在同样的监视器上执行 unlock 操作释放锁。

2024-11-25 13:38:43 909

原创 残酷的现实

而这样做的目的,都是为了提高性能。事实上左边代码的效率远高于右边的代码,这是因为通常行的数据在内存里是连续排布的,按行遍历时,该行下一列元素的缓存命中率会比按列遍历时,该列一下个元素的命中率高很多,这能极大提高程序的效率(可能会高几十倍)。这是因为单线程程序的预期运行顺序和代码的编写顺序一样,编译器预先知道了各个操作的依赖关系,因此可以在不破坏依赖关系的前提下进行重排序,而在多线程的语境下,只看代码,编译器并没有办法推断出代码的依赖关系,无法知道一个线程里的 write 操作是不是一定要在另一个线程的。

2024-11-22 11:37:40 1067

原创 理想的并发世界

我们希望“同一时刻”,只有一个线程进入临界区(#6),所以我们在 #6 之前写了很多同步的逻辑,如果程序执行能满足 Sequential Consistency,那么上面的算法就能满足,在任意时刻,线程 A/B 只有一个能进入临界区,执行 #6 中的代码(实际可能有多行)。我们需要和机器有个约定,这样当结果不符合预期时,我们好分辩是代码写错了,还是机器执行错了。考虑 CPU 多个核的执行顺序,多核的执行结果,相当于把每个核要执行的操作汇总排个序,在这个顺序里,要求每个核的操作依旧保持在单核内的相对顺序。

2024-11-22 11:25:27 1015

原创 揭秘Spring事务管理:从传播行为到隔离级别,一文读懂如何优化你的应用性能!

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,Spring是无法提供事务功能的。① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

2024-10-18 10:38:30 468

原创 Spring 如何解决循环依赖?

循环依赖:说白是一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了构成一个环形调用。第一种情况:自己依赖自己的直接依赖。第二种情况:两个对象之间的直接依赖。第三种情况:多个对象之间的间接依赖。前面两种情况的直接循环依赖比较直观,非常好识别,但是第三种间接循环依赖的情况有时候因为业务代码调用层级很深,不容易识别出来。

2024-10-10 11:29:57 919

原创 看这篇告诉你Spring如何完美的解决循环依赖

(没有属性填充、初始化),就put进去。二级缓存是对三级缓存的过渡性处理,只要通过 getObject() 方法从三级缓存的BeanFactory中取出Bean一次,原材料就变成半成品,之后put到二级缓存 , 所以,二级缓存里边的bean,都是半成品。Spring中的循环依赖,其实就是一个死循环的过程,在初始化 A 的时候发现依赖了 B,这时就会去初始化 B,然后又发现 B 依赖 C,跑去初始化 C,初始化C 的时候发现依赖了 A,则又会去初始化 A,依次循环永不退出,除非有终结条件。

2024-09-12 18:38:32 977 1

原创 面试官再问Spring的生命周期,你这么回答他

3.ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware) 这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext。阶段,主要逻辑都在doCreate()方法中,逻辑很清晰,就是顺序调用以下三个方法,这三个方法与三个生命周期阶段一一对应,非常重要,在后续扩展接口分析中也会涉及。采用了扩展的方式添加。

2024-08-26 23:19:58 1021

原创 看完这篇文章之后,面试官再也不敢问我什么是Spring的Bean了

Spring Bean 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些Bean通过容器中配置的元数据创建。比如,以XML文件中的形式定义。一个 Spring Bean 定义包含什么?一个Spring Bean 的定义包含容器必知的所有配置元数据,包括如何创建一个Bean,它的生命周期详情及它的依赖。当在Spring里定义一个Bean后,我们还能给这个Bean声明一个作用域。它可以通过bean 定义中的scope属性来定义。

2024-08-18 23:23:29 507

原创 Spring是怎么实现依赖注入的,你这么告诉面试官

控制反转IoC是一个很大的概念,可以用不同的方式来实现。其主要实现方式有两种:依赖注入和依赖查找。依赖注入:相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。所谓依赖注入(Dependency Injection),即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。

2024-08-18 22:09:19 332

原创 面试官问Spring的容器是什么?你这么回答他

BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

2024-08-09 21:48:12 1532

原创 面试官问Spring如何实现控制反转(IOC),这样告诉他

管理对象的创建和依赖关系的维护。对象的创建并不是一件简单的事,在对象关系比较复杂时,如。托管了类的产生过程,比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果。有容器,程序可以把这部分处理交给容器,应用程序则无需去关心类是如何完成代理的。,它把传统上由程序代码直接操控的对象的调用权交给容器,通。),装配对象,配置对象,并且管理这些对象。过容器来实现对象组件的装配和管理。的实现原理就是工厂模式加反射机制。来说,最重要的就是容器。解耦,由容器去维护具体的对象。其中,最重要的就是依赖注入,从。

2024-07-31 21:20:06 180

原创 特大好消息

Java后端开发的老程序员,我希望收集到全网最全的面试题,并把答案以文章的形式记录下来,形成一个面试体系,让求职者在面试时游刃有余,有的放矢。现如今正处于经济的低谷,岗位竞争激烈,面试机会本来就寥寥无几,如果因为面试题没有答好,而错失了到手的offer,则实属可惜。

2024-07-04 23:23:26 244

原创 让我来告诉你Netty是如何分配内存的

在上一篇文章我们介绍了Netty中的ByteBuf。ByteBuf是数据的存储介质,那么Netty是如何根据需要进行内存分配的呢?这是本篇文章要介绍的内容。

2024-06-22 18:08:59 948

原创 什么?你不知道Netty中的ByteBuffer是什么,我来告诉你

在Netty中存储数据和发送数据作为临时存储抽象的是ByteBuf,而在Java的NIO层面使用的是ByteBuffer。

2024-06-04 20:43:21 745

原创 面试官在问你synchronized的底层原理,你就这样回答

在后端面试时,经常会被问到 volatile 关键字可以保证原子性吗?我们肯定知道是不能保证原子性的。那么接下来面试官会问,如何保证原子性呢?要想保证原子性,就要依赖于同步机制。

2024-05-08 11:39:26 237 1

原创 看了这篇文章,妈妈再也不会担心面试官问我volatile关键字底层原理了

volatile 关键字是 JVM 提供的最轻量级的同步机制,用来修饰变量,用来保证变量对所有线程可见性。

2024-05-08 09:26:40 1808 1

原创 看了这篇文章,Java虚拟机面试吊打面试官

​Java虚拟机是参考操作系统而创建的,用于运行Java程序代码。Java虚拟机把源代码编译好的.class文件,加载到Class Loader,.class文件中的数据信息存储在运行时数据区。运行时数据区由方法区、Java栈、本地方法栈、堆、程序计数器组成。其中Java栈、本地方法栈、程序计数器是每一个线程所独有的,堆和方法区是所有线程共享的。

2024-04-08 11:30:20 687

原创 看这一篇就够了,全网最全、最强分析Spring是如何创建对象的

如果没有用Spring框架,程序员创建对象的方式有以下5种方式:使用new关键字。 使用Class的newInstance()方法。 使用Constructor的newInstance()方法。 使用clone()方法。 使用反序列化。虽然这些方式都能实现创建一个对象,但在当今的应用开发中对于频繁使用到的类(比如dao层对象),如果频繁的创建对象,无形中会加剧内存的产生,对系统性能产生影响,而且也是不利于管理的。为了解决上述提到的痛点,Spring就应运而生,并且业界在进行企业级开发的时候,都

2023-12-21 09:18:03 225

原创 线程的生命周期

创建WaitingState类,此线程会在一个while(true)循环中,获取当前类Class对象的synchronized锁,也就是说,这个类无论创建多少个实例,synchronized锁都是同一个,并且线程会处于等待状态。一个线程从创建,到最终的消亡,需要经历多种不同的状态,而这些不同的线程状态,由始至终也构成了线程生命周期的不同阶段。为了更好的理解线程的生命周期,以及生命周期中的各个状态,接下来使用代码示例来输出线程的每个状态信息。启动各个线程,验证各个线程输出的状态,代码如下所示。

2023-08-23 12:23:39 139

原创 Spring创建对象的过程

当我们用以下代码创建一个Spring容器时,都做了什么呢?在AnnotationConfigApplicationContext的构造方法中会调用this()构造方法。在这个构造方法中会实例化一个ClassPathBeanDefinitionScanner对象。这个扫描器对象的scan()方法,就是用来扫描用户在xml中配置的信息或者在配置类上标注的注解。scan()方法里的核心方法是doScan(basePackages)。

2023-07-29 16:30:13 328

原创 Kafka Producer 初始化

使用kafka向MQ中发送数据,首先需要构建一个Producer(生产者)实例。我们一般在自己的代码中直接调用Producer类的构造函数进行创建,这也是Kafka进行Producer初始化的入口,我们先来用一个流程图来分析一下Producer初始化的流程。接下来把构建KafkaProducer实例的核心过程用一个脑图来梳理一下。以上就是KafkaProducer初始化的核心流程。

2023-03-10 16:21:51 378

原创 kafka内存池设计的艺术

在新版的Kafka Producer中,设计了一个内存缓冲池,在创建Producer时会默认创建一个大小为32M的缓冲池,也可以通过buffer.memory参数指定缓冲池的大小,同时缓冲池被切分成多个内存块,内存块的大小就是我们创建Producer时传的batch.size大小,默认大小16384,而每个Batch都会包含一个batch.size大小的内存块,消息就是存放在内存块当中。该方法的作用根据给定的size,在BufferPool中分配一个buffer。新版本的kafka是由Java语言实现的。

2023-01-06 15:43:48 607 1

原创 这一次我真的懵逼了

我这半年在一家零售行业公司做研发工作,合同签订了三年,试用期是半年。因为知道在新冠疫情的大背景下工作难找,对于这个工作机会格外的珍惜,并且兢兢业业。经过了无数的员工培训,转正答辩,疫情影响小区封控的情况下,居家办公也丝毫没有怠慢,连续两个项目保证质量,往前赶项目进度,甚至提前项目生产上线。5月22日收到了转正的邮件,成为了正式员工,转过天,5月23日就被领导和HRBP约到会议室,进行解约谈判。我一下子不知道怎么回答了。追问他们给我一个合理的理由,得到的理由是疫情影响,许多的项目进不来,要进行优化。试问,疫情

2022-05-31 14:11:16 140

原创 AbstractQueuedSynchronizer 源码分析 (基于Java 8)

AbstractQueuedSynchronizer 定义AbstractQueuedSynchronizer 是JUC 中通过 Sync Queue(并发安全的 CLH Queue),Condition Queue(普通的 list) , volatile 变量 state 提供的控制线程获取统一资源(state) 的 Synchronized 工具。...

2020-04-26 22:04:14 205

原创 Netty学习总结(一)

如果用Java语言进行网络程序开发,有BIO(阻塞式IO)和NIO(非阻塞式IO)两种方式。用一个场景来解释BIO就是,你打电话给朋友拜托他去做一件事情,交代完之后,你没有挂断电话,而是一直等着他给你回信。而NIO则是交代之后,挂断电话去做别的事情,等朋友完成任务之后,在打电话通知他。通过上面的场景描述,给人感觉使用NIO进行网络编程,更加符合现实生活的习惯,以及更加的高效。除此之外如果处理几...

2019-09-16 15:22:11 214

原创 初识IoC

Spring的两大核心概念一个是InversionofControl,一个是DependencyInjection。我们先来梳理一下什么是IoC?IoC的抽象概念是“依赖关系的转移”。例如程序中有两个类A和B。A类中要使用B类中定义的方法,我们通常的做法是在A类中实例化B类一个对象,从而达成调用B类方法的目的。这样做会产生什么问题呢?这样的设计方式,会让A类依赖于B类,也就是说高层模块不应该...

2019-04-08 11:25:25 172

mybatis-demo

MyBatis入门示例,告诉大家如何快速的使用这一个轻量级的持久化解决方案。

2016-06-16

在线点餐系统

系统使用JavaBean+Servlet技术,数据库使用JDBC访问方式。绝对可用!

2012-12-24

BBS论坛设计论文

一份非常详尽的系统设计文档,只要低价就可以分享,获得宝贵经验。

2012-04-12

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除