- 博客(43)
- 收藏
- 关注
原创 返璞归真之重拾SpringAop
AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构.OOP(Object Oriented Programming)面向对象编程作用:在不惊动原始设计的基础上为其进行功能增强。简单的说就是在不改变方法源代码的基础上对方法进行功能增强。Spring理念:无入侵式/无侵入式(在不改变原有业务代码的情况下,完成相应的逻辑校验处理等.)
2025-01-25 16:55:23
478
原创 返璞归真--重拾JDBC
JDBC就是使用Java语言操作关系型数据库的一套API.全称是JavaDataBaseConnectivity.就是java数据库连接.Jdbc使用1.注册驱动2.获取数据库连接3.编写sql语句4.获取执行sql语句的对象5.执行sql语句,并接收结果6.处理结果7.释放资源//1.注册驱动.用到了java的spi机制.//2.获取数据库的连接.//3.获取数据库连接.//4.编写sql语句.//5.获取执行sql语句的对象//6.执行sql语句,并接受结果.
2025-01-19 13:44:39
504
原创 Spring底层源码(六)之循环依赖
前面的文章讲过了Bean的生命周期,可以联想到Bean的创建其实是挨个创建然后进行属性的注入,这样思考的话就会存在循环依赖的问题.A依赖B,B依赖C,C依赖A.这样就会导致有一个属性无法完成注入.然后通过简单了解八股文我们会知道,Spring会用过一级缓存 二级缓存 三级缓存来完成.从实现角度来考虑一层缓存或者两层缓存就可以解决,为什么要三层.具体哪三层.我们通过源码来了解下.这个方法进行判断是否会产生循环依赖,具体怎么会产生呢.如果这个bean没有正在创建中.并且是单例的,而且容器中允许存在循环依赖
2024-12-02 23:35:17
310
原创 Spring底层源码(五)依赖注入
这个是去进行筛选.直接进入它默认的实现类.我们的类型也可能会是map list这些集合,进行符合条件的bean注入.所以这块都会进行相应的处理.这个流程就是对属性的注入.知道了大概思路,剩下的就是反复的调试细节.上一篇文章说了Bean的生命周期,然后我们知道了什么时候开始注入,那就是填充属性的时候.填充属性关于注入的方法代码块如下.我们的成员变量也支持@value注解进行注入.里面的值是占位符,所以这块也会进行相应的解析.然后上面的inject方法的实现分为方法和成员变量的.我们以成员的为主.参考如下.
2024-11-23 23:04:55
419
原创 Spring底层源码(五)依赖注入之寻找注入点
2:实例化 会把对应的Bean对象创建出来.只是一个空对象,没有属性.然后会调用SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors方法获得所有的构造方法.4:初始化前 会调用SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference的方法.这个方法不光会处理循环依赖,还会找到所有的切点.提前进行Aop.5:填充属性. 把找到的注入点进行属性的设置.
2024-11-19 20:50:17
281
原创 Spring底层源码(四)FactoryBean
从源码可以看出 FactoryBean是一个接口.里面有三个方法供子类去实现.其中比较重要的是getObject方法.它可以直接创建一个对象返回.还有getObjectType方法,它可以返回创建对象的类型.看transformedBeanName(name)方法,它是判断一个BeanName是不是以&开头的.如果是的话,则会进行截取.参考源码如下.从结果可以看出,成功获得了一个对象,并且是我们FactoryBean的getObject方法返回来的对象.上面代码上都有注释,我直接进入正题.参考如下图.
2024-11-16 20:12:01
303
原创 Spring底层源码(三)
这个方法内部会判断传入的类上是否有Conditional注解.如果有的话,就会判断是否符合注解内的条件.这个注解衍生SpringBoot里用的比较多.后面讲SpringBoot会详细介绍.因为主要看如何扫描,其余的看注释就好,直接进入重点了. 找到如下代码处.接下来的逻辑,就不多啰嗦了,可以看上面的注释.直接进入正题.首先进入shouldSkip这个判断方法.具体源码如下.这个方法里面会进行配置类的扫描.具体源码如下.顺着这个方法往进点.就能找到如下图.进入这个方法以后,具体的源码如下.
2024-11-12 22:54:50
387
原创 Spring底层源码(二)refresh模板方法
总结一下就是这个方法就是在找BeanFactoryPostProcessors,然后进行执行前置后置的方法.其中配置类的扫描就是在这里执行的.具体的实现类是 ConfigurationClassPostProcessor,可以点进去看一下.这个方法的内部是一个空实现.需要由子类来进行实现.从名字可以看出来这个方法是对BeanFactory进行的一个增强. 具体可以参考子类的实现.这个方法是个空实现,用于交给子类实现.SpringBoot中就是通过这个方法启动的Tomcat.这个方法就是进行事件的发布.
2024-11-10 20:42:10
557
原创 手写Spring源码
这个大概就是Spring的一个基础流程.可以参照上一篇文章进行对比学习.不懂没关系.后面还会继续分析具体的源码.上一节学习Spring源码,会有一个ApplicationContext,所以先写一个容器对象.参考代码如下.注解基本上都是参照Spring的定义来的.
2024-11-09 23:39:47
320
原创 Spring底层源码(一)
因为AnnotationConfigApplicationContext是比较重要的,并且AnnotationConfigApplicationContext和ClassPathXmlApplicationContext大部分底层都是共同的.所以我们就分析AnnotationConfigApplicationContext的流程.这里是注册了一些最基本的PostProcesser,切记切记,一定要有个印象.(可以手动注册,也可以利用配置bean的方式,不懂,先记住.方便后面理解)
2024-11-07 21:06:26
720
1
原创 异步调用之FutureTask
使用FutureTask实现异步泡茶喝,main线程可以获取烧水线程 清洗线程的执行结果,然后根据结果判断是否具备泡茶条件,如果具备泡茶条件在泡茶.启动Thread实例的run方法,会执行FutureTask实例的run方法,最终会执行到Callable实现的call方法.4:调用Thread实例的start()方法启动新线程,启动新线程的run()方法并发执行.其内部的执行过程为.1:创建一个Callable接口的实现类,并实现call方法,编写好异步执行的具体逻辑,并且可以有返回值.
2024-11-03 11:51:38
431
原创 异步回调之Join
总结下,join方法通过上面的源码可以看出,是不断通过检查线程是否存存活,来进行阻塞.直到被唤醒才会解除阻塞.而且join方法不能拿到返回结果,缺少很多的灵活性.所以join更多的停留在Demo演示上.Java中线程的合并流程是:假设线程A调用线程B的join()方法去合并B线程,那么线程A进入阻塞状态,直到线程B执行完成.A线程调用B线程的join方法,等待B线程执行完成,在B线程没有完成之前,A线程阻塞.A线程等待B线程执行一段时间,最长时间为millis 毫秒,超过后就会A线程重新执行.
2024-11-02 20:59:11
452
原创 高并发设计模式之ForkJoin模式
分而治之是一种思想,所谓分而治之就是把一个复杂的算法问题按一定的分解方法分为规模较小的若干部分,然后逐个解决,分别找出各部分的解,最后把各部分的解在整合成整个问题的解.ForkJoin模式就是分而治之思想的另一种应用.
2024-10-31 22:44:54
912
原创 高并发设计模式之生产者-消费者模式和Future模式
生产者和消费者是两个独立的并发体,生产者把制造出来的数据往缓冲区一放,就可以生产下一个数据.生产者基本上不用依赖于消费者的消费速度.如果生产过快,消费者可以平缓的进行处理.比如阻塞队列和MQ等就是生产者消费的例子.Future模式的核心思想是异步调用.有点类似于异步的Ajax请求. 当调用某个耗时的方法时,可以不急于立刻获取结果,而是让被调用者立刻返回一个契约,并且将耗时的任务放到另外的线程执行.后续在凭契约来获取结果.
2024-10-26 12:27:21
478
原创 高并发设计模式之Master-Worker模式
Master-Worker模式是一种常见的高并发模式.核心思想是任务的调度和知行分离.调度任务的角色为Master,执行任务的角色为Worker.Master负责接收和分发合并任务.Worker负责执行任务.整体架构如下图.
2024-10-23 23:53:18
371
原创 并发设计模式之单例模式
单例模式加锁操作只有单例在第一次创建的时候才需要用到,之后的单例获取操作都没必要在加锁.所以可以先判断单例对象是否被初始化,如果没有在加锁初始化.参考如下.缺点:单例对象在类被加载的时候,实例就直接被初始化了.很多时候在类被加载的时候并不需要进行单例初始化.所以需要对单例的初始化予以延迟.参考代码如下.3:进入临界区后,再一次检查对象是否被初始化,如果没有被初始化就初始化一个实例,相反就返回这个实例.这是第二次检查.1:检查单例对象是否被初始化,如果初始化,立即返回单例对象.这是第一次检查.
2024-10-20 11:12:57
892
原创 BlockingQueue详解
如果该队列已有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。同样,如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。LinkedBlockingDeque 是一个双端队列,在它为空的时候,一个试图从中抽取数据的线程将会阻塞,无论该线程是试图从哪一端抽取数据。一个线程往阻塞队列里放资源.另一个线程进行消费.如果队列满的话,放入的线程会被阻塞.相反.如果队列为空,消费的线程就会被阻塞.。
2024-10-14 23:11:27
1251
原创 ReentrantReadWriteLock源码讲解
此函数用于获取写锁,首先会获取state,判断是否为0,若为0,表示此时没有读锁线程,再判断写线程是否应该被阻塞,而在非公平策略下总是不会被阻塞,在公平策略下会进行判断(判断同步队列中是否有等待时间更长的线程,若存在,则需要被阻塞,否则,无需阻塞),之后在设置状态state,然后返回true。否则,将设置当前线程对应的HoldCounter对象的值.HoldCounter主要有两个属性,count和tid,其中count表示某个读线程重入的次数,tid表示该线程指定线程id.用来唯一标识一个线程.
2024-10-12 23:43:10
1163
原创 ReentrantLock源码
现在真的很喜欢孙中山的自勉联,愿乘风破万里浪,甘面壁读十年书.普普通通一句话,好的心态,面对世俗的质疑,对前方的执着. 弃医从文,不仅仅是魄力,更是认知的转变.更是知与行的诠释.愿吾自立自强,不朽.t1线程的lock操作 -> t2线程的lock操作 -> t3线程的lock操作 -> t1线程的unlock操作 -> t2线程的unlock操作 -> t3线程的unlock操作.从lock方法的源码可知,每一次都尝试获取锁,而并不会按照公平等待的原则进行等待,让等待时间最久的线程获得锁。
2024-10-07 19:18:29
1328
原创 AQS机制详解
执行案例的运行结果.(其中之一) 线程t1先执行lock操作,获取锁.然后线程t2执行lock操作.然后t1进行unlock操作,然后t2获取锁成功,接着执行unlock操作. t1线程调用lock.lock方法,方法调用顺序.t2线程调用lock.lock方法,其方法调用顺序. 最后的结果是被阻塞.源码如下. t1线程调用lock.unlock,其方法调用顺序.t1线程中调用lock.unlock后,经过一系列的调用,最终的状态是释放了许可,因为调用了LockSupport.unpark。这时,t2线程
2024-10-05 12:46:24
791
原创 AQS讲解
AQS是一个并发的得同步器.JUC包下的ReentrantLock,Semaphore,ReentrantReadWriteLock,SynchronousQueue,FutureTask等底层都是基于AQS实现的.我们也可以通过AQS实现自己的并发工具类.
2024-10-04 19:51:04
1124
原创 Phaser源码讲解
如果当前操作不是首次注册,那么直接在当前phaser上更新注册parties数如果是首次注册,并且当前phaser没有父节点,说明是root节点注册,直接更新phase如果当前操作是首次注册,并且当前phaser由父节点,则注册操作交由父节点,并更新当phaser的phase上面说过,子Phaser的phase在没有被真正使用之前,允许滞后于它的root节点。在终止时,所有同步方法立刻返回一个负值。如果当前phaser有父节点,并且当前phaser上没有已注册的party,那么就会交给父节点注册。
2024-10-03 10:59:07
686
原创 CyclicBarrier源码分析
说明: 由于ReentrantLock的默认采用非公平策略,所以在dowait函数中调用的是ReentrantLock.NonfairSync的lock函数,由于此时AQS的状态是0,表示还没有被任何线程占用,故main线程可以占用,之后在dowait中会调用trip.await函数,最终的结果是条件队列中存放了一个包含main线程的结点,并且被禁止运行了,同时,main线程所拥有的资源也被释放了,可以供其他线程获取。头节点与尾节点均指向它。此函数的作用是损坏当前屏障,会唤醒所有在屏障中的线程。
2024-09-22 14:35:56
867
原创 CountDownLatch源码分析
从源码可知,其底层是由AQS提供支持,所以其数据结构可以参考AQS的数据结构,而AQS的数据结构核心就是两个虚拟队列: 同步队列sync queue 和条件队列condition queue,不同的条件会有不同的条件队列。CountDownLatch典型的用法是将一个程序分为n个互相独立的可解决任务,并创建值为n的CountDownLatch。当每一个任务完成时,都会在这个锁存器上调用countDown,等待问题被解决的任务调用这个锁存器的await,将他们自己拦住,直至锁存器计数结束。
2024-09-21 22:08:07
697
原创 CompletableFutuer异步回调
CompletionStage接口代表异步计算过程中的某一个阶段,一个阶段完成后会进入另一个阶段.一个阶段可以理解为一个子任务,每个子任务会包装一个Java函数式接口实例,表示该子任务要执行的操作.Function接口的特点,有输入有输出,包装了Function实例的CompletionStage的子任务需要输入一个参数,并会产生一个输出结果到下一步.Consumer接口的特点是,有输入无输出.包装了Consumer实例的CompletionStage的子任务需要输入一个参数,但不会产生任何输出.
2024-09-13 22:45:53
658
原创 JAVA反射详解
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意属性和方法;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
2024-09-07 22:46:30
466
原创 Java泛型机制详解
1:<?> 无限制通配符.2:<?extends E> extends 关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类.3:<?super E> super 关键字声明了类型的下界,表示参数化的类型可能是指定的类型,或者是此类型的父类.有了方向,还会怕走错路嘛.如果大家喜欢我的分享的话,可以关注我的微信公众号心有九月星辰。
2024-08-25 19:53:22
635
原创 Synchronized重量级锁原理和实战(五)
在JVM中,每个对象都关联这一个监视器,这里的对象包含可Object实例和Class实例.监视器是一个同步工具,相当于一个凭证,拿到这个凭证就可以进入临界区执行操作,没有拿到凭证就只能阻塞等待.重量级锁通过监视器的方式保证了任何时间内只允许一个线程通过监视器保护的临界区代码.
2024-08-20 22:53:40
1282
原创 synchronized轻量级锁原理和实战(四)
因为内置锁对象的Mark Word的结构会有所变化,Mark Word将会出现一个指向锁记录的指针,而不再存着无锁状态下的锁对象的哈希码等信息,所以必须将这些信息先暂存起来,供后面使用.抢锁线程先处理好栈帧中的轻量级锁记录,然后就是最核心的CAS自旋.抢锁线程通过自旋操作,尝试将内置锁对象头的Mark Word的ptr_lock_record(锁记录指针)更新为抢锁线程中锁记录的地址.如果更新成功了,这个线程就拥有了这个对象锁.然后JVM会把Mark Word的锁记录标记位改为00(轻量级锁标志).
2024-08-18 22:25:49
1067
原创 synchronized偏向锁原理和实战(三)
偏向锁的加锁过程为:心线程只需要判断内置锁对象的Mark Word的线程ID是不是自己的ID.如果是就直接使用这个锁.不用做CAS操作交换.如果不是,比如在第一次获得此锁时内置锁的线程ID为空,就使用CAS进行操作交换,新线程将自己的ID交换到内置锁的Mark Word中,交换成功就加锁成功.如果JVM检查到原来的线程依然存活,就表明原来的线程还在使用偏向锁,发生锁竞争,撤销原来的偏向锁,将偏向锁膨胀为轻量级锁.如果锁对象被多个线程竞争,偏向锁就是多余的,并且其撤销过程会带来一些性能上的开销.
2024-08-14 22:08:02
1132
原创 synchronized运用理解(二)
通过分离变与不变的原则,通过这种方式不同的生产者和消费者公共部门拆分出来,只需要在构建生产者消费者的时候传入对应的动作就可以.增强了灵活性.3:数据缓冲区是线程安全的.在并发操作过程中不会出现数据不一致的情况,或者多线程操作并发更改数据后,不会造成出现脏数据的情况.生产者线程和消费者线程在实际运行发生的问题.生产者不断生产数据放到缓冲区,消费者不断地去缓冲区消费数据.2:数据缓冲区是有上限的,数据满后,生产者不能再加入数据.缓冲区为空的话,消费者不能再取出数据.从运行结果可以看出出现了共享数据不一致问题.
2024-08-11 21:28:14
471
原创 synchronized关键字(一)
每个java对象都隐含有一把锁,这里称为java内置锁,使用synchronized关键字相当于获取了一把内置锁,对临界区进行排他性保护.
2024-08-07 23:25:36
924
原创 ThreadLocal原理(二)
ThreaddLocal源码方法不是很多,主要有get()方法,set(T value)方法,remove()方法,initialValue()方法.
2024-08-04 22:46:27
898
原创 ThreadLocal原理(一)
了解过HashMap的话,会知道在扩容的时候存在高成本低性能的问题.因为HashMap内部是一个槽位(slot)数组,这个数组也叫哈希表,存储的是key的哈希值,当槽位数组中的元素个数超过默认容量(16)乘以加载因子(0.75)的时候会进行扩容,扩为容量为32的数组.对于每一个槽位,可以理解为桶(bucket),如果一个桶内元素超过8个,链表会变成红黑树,这是都是高性能低成本的工作.可以为每一个线程绑定一个Session(用户会话)信息,一个线程所访问的地方可以很方便的访问这个本地会话.
2024-08-02 23:41:10
1000
原创 线程池的原理和使用(三)
SynchronousQueue是一个比较特殊的阻塞队列实现类.没有容量,每一个插入操作都对应着删除操作,反之每个删除操作都对应着插入操作.也就是说,提交的任务不会被保存,而是将新任务交给空闲线程执行,如果没有空闲线程就创建一个新的线程,如果线程数已经大于最大线程数,就执行拒绝策略.使用这种阻塞队列就需要把最大线程数设置的很大.而这个线程池的最大问题就在最大线程数量不设上限.如果任务提交过多会造成OOM异常,甚至因为线程过多,造成资源耗尽.
2024-08-01 20:24:21
781
原创 线程池的原理和使用(二)
Override//做日志记录等.System.out.println("任务" + r + "-getTaskCount:"//可以自己搞一个线程自己处理.这块完全可以发挥自己的想象力,比如发送mq 发送邮件其实都是可以的.
2024-07-31 23:47:23
1555
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人