Java 8 之后都更新了些什么

前言

我最开始学 Java 是在 2017 年,那时候距离 Java 8 正式发布(2014年)已经过去3年了,因此我是直接从 Java 8 开始学习的。然而时至今日(2023年),我在网上仍然可以看到不少文章在介绍 “Java 新特性 - Stream、Lambda表达式”,拜托,那些都是快10年前的东西了,但还是有好多人固执地认为这些就是 Java 的最新特性。

这几年在公司里也见到不少项目仍然使用 Java 6,到了不得不升的时刻,也只敢升到 Java 8,而不敢进一步往上升了。很多程序员依然遵循着「你发任你发,我用Java 8」的原则。看来大家对 Java 8 真是爱之入骨。

那么,假如你是一个新项目的负责人,在新项目里你可以使用全新的技术栈而不用担心历史包袱,你敢不敢尝试新技术呢?要做出选择,这不得先了解一下 Java 8 之后,Java 主要都更新了些什么。

阅读更多

从一次线上问题聊聊缓存使用

最近运维转发过来一封线上告警邮件,大概是说,我们负责的系统线上环境有一个接口隔一段时间就频繁报错,但持续十分钟左右就自动恢复了。从监控工具看到,每次报错出现时,都是同一台实例报出来的,此时其他实例是正常的,但下一次可能是另一台实例出现相同的问题,非常奇怪。

阅读更多

Effective Java(十)并发

如果你想获得更高的性能,使用并发是不可避免的。但是并发编程要比单线程编程难得多,一方面它很容易出错,另一方面错误很难复现。这一篇主要介绍如何写出正确、简洁、可靠的并发程序。

阅读更多

Java中的浅拷贝和深拷贝

引言

最近在复审代码时,发现组内一个同学写了这么一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void process(ResultContext rc){

Map m1 = rc.getResult();
Map m2 = rc.getResult();

// m1 做一些get set处理
// ..

// m2 做一些get set处理
// ..

dao.insert(m1);
dao.insert(m2);
}

这段代码,本意是想从同一个 ResultContext 获取到原始数据,然后对这份数据做不同的加工,再分别保存。但这段代码实际上是有问题的。因为 m1m2 虽然是不同的引用,但实际上都指向了同一个对象,在修改 m1 的同时, m2 实际上也发生了改变,反之亦然

阅读更多

记一次Spring JDBC内存泄漏引起的线上事故

问题再现

最近在维护一个基于 Spring Boot 的数据同步系统。项目使用 druid 连接池,配置动态数据源连接了 16 个数据库,主要用于跑任务处理跨库数据同步。其中的某个任务,在线上环境一直稳定运行,前几天任务又一次执行时,突然收到任务报错的邮件告警。

阅读更多

MyBatis大批量数据处理

前言

最近项目里需要跨数据库同步大批量数据(百万到千万级别),以前都是用 JDBC 来实现。在 JDBC 里,我们能灵活地使用流查询来批次摄取处理,避免OOM,但 JDBC 这玩意儿写多了,谁都会嫌它既啰嗦又繁琐(但性能真香)。于是这次决定用 Springboot + Mybatis 框架来试试。因为涉及到多个数据源和不同的数据库产品(Oracle、PostgreSQL、MySQL),所以在项目里使用了动态数据源。

关于 Springboot 多数据源方案,我参考过最好的文章为下面的3连载,推荐一看。

至于使用 Mybatis 做大批量数据读取和插入,先前也是阅读了大量的参考资料和文档。总体思想跟 JDBC 是一致的,即:流式查询、批次插入。但在讲 Mybatis 之前,先回顾一下 JDBC 时代是怎么做的吧。

阅读更多

Java并发编程之AQS

什么是 AQS

同步工具类 也叫同步器(Synchronizer)。在使用同步器时,我们发现不同的同步器存在许多共同点,例如 ReentrantLock 和 Semaphore 都支持每次允许一定数量线程通过/等待/取消,也都支持让等待线程执行公平或非公平的队列操作等。

事实上,很多同步工具类在实现时都使用了共同的基类,这就是 AbstractQueuedSynchronizer(AQS),抽象队列同步器

阅读更多

Java并发编程之对象共享

对象数据共享

要实现多个线程之间的数据共享,需要考虑两个问题:

  • 通信:通信是指消息在两条线程之间传递
  • 同步:既然要传递消息,那 接收线程发送线程 之间必须要有个先后关系。此时就需要用到同步,即控制多条线程之间的执行次序。
阅读更多