
Java核心
文章平均质量分 93
Java基础讲解,关于Java的方方面面,包括IO、网络、正则、泛型、函数式编程、安全、Instrument、Tools API
randy.lou
你若盛开,清风自来
展开
-
Java核心: JarIndex的使用
在讲解的时候,我们发现URLClassLoader加载类或资源时通过访问ClassPath下的每一个路径,来确定类是否存在的,假设我们执行的命令是这样的如果我们代码里使用了org.springframework.boot.loader.launch.Archive,我们的类加载器会依次尝试在每个ClassPath下每个元素一个复杂的大型项目依赖几十个上百个第三方jar是很常见的,总是这么查找显然是极其低效的。原创 2024-06-10 13:42:56 · 1399 阅读 · 0 评论 -
Java核心: 类加载器
这一节我们来学习Java的类加载器,以及常用的类加载器实现URLClassLoader。原创 2024-06-09 22:52:34 · 1042 阅读 · 0 评论 -
SpringBoot: 启动流程和类装载
前面我们学过Spring定制了自己的可执行jar,将真正执行时需要的类和依赖放到BOOT-INF/classes、BOOT-INF/lib来,为了能够识别这些为止的源文件,Spring定制了自己类加载器,本节我们来讲解这个类加载器。原创 2024-06-09 22:26:46 · 1771 阅读 · 1 评论 -
Java核心: 为图片生成水印
今天干了一件特别不务正业的事,做了一个小程序用来给图片添加水印。事情的起因是有人管我要身份证照片,手边并没有一个趁手的工具来生成图片水印。很多APP提供了水印的功能,但会把我的图片上传到他们的服务器,身份证太敏感了,显然我并不想让别人有机会保留照片。我把图片处理做了一个抽象,入参是BufferedImage,对图片添加水印、盲印、隐式写入后返回新的BufferedImage作为结果。原创 2024-06-06 21:45:38 · 641 阅读 · 0 评论 -
Java核心: 使用instrumentation
接下来我们要做的是定义一个最简单的instrumentation实现,仅仅是打印-javaagent后带的参数,以及执行过程加载的所有的类、它所属的ClassLoader。首先要做的是创建工程,后续用于打包成agent的jar,这里我们命名为AsmToString.jar。这里使用mvn archetype:generate创建工程为了让-javaagent能使用这个jar,需要在MANIFEST.MF里添加Premain-Class的定义。原创 2024-05-29 10:10:18 · 1268 阅读 · 0 评论 -
Java核心:注解处理器
首先我们需要定义一个注解,用来标注后续要生成toString方法的类。@ToString的逻辑很简单,这里我们只把它定义为一个标记注解。定义@ToString注解之后,我们就可以把它用在想要自动生成toString方法的类上,比如我们有一个Point类的定义,我们希望为Point类生成toString方法,可以在Point上添加@ToString注解@ToStringreturn x;return y;原创 2024-05-26 21:43:12 · 1085 阅读 · 0 评论 -
Java核心: 脚本引擎和动态编译
静态语言和动态语言的在相互吸收对方的优秀特性,取人之长补己之短。脚本引擎和动态编译就是其中一个关键特性,扩展了Java的能力边界。原创 2024-05-26 13:56:30 · 1473 阅读 · 0 评论 -
Java核心: Stream流的实现原理
Java 8之后我们对Stream的操作已经习以为常了,它帮助我们从怎么做的细节里脱身,只需要告诉它做什么即可。这一篇文章我们主要讲讲Java Stream的实现原理,自己手写一个Stream框架,然后再来讲解Java Stream的核心类,做到知其然知其所以然。我们先看一个Stream使用案例,假设用一堆字符串创建流(of),取前5个(limit)、操作每个字符串取首字母(map),最后用终结操作符收集所有的首字母到List中(collect)。原创 2024-05-22 18:21:32 · 1551 阅读 · 0 评论 -
Java并发: 我所经历过的坑
我们用下面这段代码模拟了这种场景,首先我们定义了一个LongWait类,目的是让它占用线程池的线程,好让线程池没有线程可用,走RejectedExecutionHandler的逻辑。可以看到Broken运行之前,有一个timer-thread-线程,但是Broken运行后,这个线程就丢失了,连带着Timer运行异常,HeartBeat不再打印。下面是调度代码,通过日志能看到的是future.get()一直没有返回,最后的一个代码无法输出,具体看下面的线程堆栈信息。===持续更新,也欢迎提供案例===原创 2024-05-21 17:54:22 · 600 阅读 · 0 评论 -
Java并发: 锁和同步
前面我们通过LockSupport实现了一个简单的独占锁FIFOMutex,但是功能比较简易。Java内部通过了一个类似的实现,只需要覆写少数方法就能创建一个功能强大的锁,AbstractQueueSynchronizer类似于FIFOMutex,AQS也维护了一个内部状态state,将等待锁的线程通过一个CLH队列保存,额外提供ConditionObject对象,支持基于条件的等待还唤醒,同时它还支持共享锁。原创 2024-05-21 10:38:01 · 1639 阅读 · 0 评论 -
Java并发: 基于Unsafe的CAS实现无锁数据结构
为了方便测试和对比,我们事先定义了ID接口,里边只有一个方法incrementAndGet: 自增并返回int值。原创 2024-05-19 11:55:26 · 1113 阅读 · 0 评论 -
Java并发: 面临的挑战
关于ABA问题,我们举个例子来看,时间点1,线程1和线程3都读取到变量v的值1;编译成字节码后并没有看起来这么简单,对应的字节码如下(删除了Code里部分字节码),它会被拆成4步,加载id的值(Code:2),加载常量1(Code:6),将id和1相加(Code:7),写入到id字段(Code:8)想想我们在数据库使用乐观锁时SQL是怎么写的,是不是感觉有异曲同工之妙呢,oldStock就是expected,newStock就是x,version一般都是单调递增的,提供了更强的保护,避免ABA问题。原创 2024-05-19 08:32:06 · 950 阅读 · 0 评论 -
Java并发: 线程线程池和回调
被绑定的平台线程有个名字叫carrier。我们通过操作系统执行一个可执行程序时,比如Shell下执行echo,Shell会通过系统条用fork()创建一个新的进程,再通过exec()系统调用读取可执行文件ELF,用其中的数据布置现场,将其中的指令初始化栈和PC计数器,分时调度到当前进程的时候,就可以执行当前进程对应的CPU指令集了。在基于平台线程的时候,这种方法确实是奏效的,因为平台线程的个数是有限的,而且往往会使用线程池,因此经过特定次数的初始化后,就不再需要创建新的SimpleDateFormat了。原创 2024-05-17 22:53:19 · 1407 阅读 · 0 评论 -
Java泛型,这一篇就够了
之前的案例里我们已经看到泛型类( RawArray$Pair)的定义了,泛型类的类型参数不能用到静态方法上。我们来看一下泛型方法的定义,类型参数放到修饰词之后,返回值之前,看示例的of方法。通常调用泛型方法时我们不需要明确地知道类型参数,编译器自己能通过入参/返回值接收对象的引用推断出类型参数。r.key = k;return r;通过这么使用我们定义的泛型方法继承自Throwable的类不能是泛型类型,catch的括号里不能用类型变量。原创 2024-05-13 08:00:56 · 1315 阅读 · 0 评论