Victor's Code Journey
Victor's Code Journey

小白鼠试毒法-向小白鼠致敬

1000瓶药水,1瓶有毒药,服用后一小时毒发,毒药可以无限稀释,那么一小时内用几只小白鼠能够找出毒药1

一只老鼠的状态是2种生或死,这里可以看做bit位,而1000瓶药水有1000种情况,显然我们可以使用2^10 = 1024>1000 来描述这1000种可能,而2进制数的唯一性可以唯一确定一种情况。

算法之bitMap

bitmap适用于什么场景?

bitmap的核心思想是将一个元素的可能取值映射为某个空间内的值(常见的是1bit空间,提供0,1两种状态。或是2bit空间,提供 0,1,2,3四种状态)。通过某种顺序的映射表来节省存储空间。

linux命令tmpreaper

tmpwatch 会在指定目录中递归删除指定时间段内未被访问的文件。通常,它用于自动清除临时文件系统目录,例如 /tmp/var/tmp

  • 它只会删除空目录、常规文件和符号链接。它不会切换到其他文件系统,并避开了属于根用户的 lost+found 目录。
  • 默认情况下,tmpwatch 会根据文件的 atime(访问时间)而不是 mtime(修改时间)删除文件。
  • 可以在 tmpwatch 命令中添加其他参数来更改这些行为。

警告: 不要在 / 中运行 tmpwatchtmpreaper,因为该程序中没有防止这种情况的机制。

Java源码解析-Timer

(JDK version:1.8)使用Timer执行定时任务很简单:

Timer timer = new Timer();
TimerTask task = new TimerTask() {
    @Override
    public void run() {
        System.out.println("hello world");
    }
};
timer.schedule(task, 10, 2000);// 延迟10ms后每隔2s就执行一次timer task

下面我们来来分析Timer的源码。

Java并发之线程池-ScheduledThreadPoolExecutor

本篇是关于延时线程池的源码分析(JDK1.8)。ScheduledThreadPoolExecutor继承了ThreadPoolExecutor类,实现了ScheduledExecutorService接口。ScheduledThreadPoolExecutor 支持延后执行给定task,或是定期执行。任务在到时间后执行,但是没有任何的实时保证。对于计划执行时间相同的任务,会按照提交顺序,先进先出执行。

Java虚拟机-SafePoint

A point in program where the state of execution is known by the VM。

HotSpot的安全点定义: Safepoint 是程序执行过程中的一个点,在这个点,所有的GC根都是已知的,所有的堆对象内容都是一致的。从全局角度来看,所有的线程都必须在安全点阻塞,然后GC才能运行。(作为一种特殊情况,运行JNI代码的线程可以继续运行,因为它们只使用句柄。在安全点期间,它们必须阻塞而不是加载句柄的内容。)从局部角度来看,安全点是代码块中的一个特别点,执行线程可能会在该点阻塞GC。大多数执行点都符合安全点的条件。每个安全点都有强不变量,这些不变量在非安全点可能会被忽略。

总而言之,Safepoint 指在 Java 虚拟机中,程序执行时的一个特殊点。在 Safepoint 处,所有的线程都会被暂停下来,以便进行JVM 的一些特定的操作1。例如:

  • 定时进入 SafePoint:经过-XX:GuaranteedSafepointInterval配置的时间,都会让所有线程进入 Safepoint,一旦所有线程都进入,立刻从 Safepoint 恢复。这个定时主要是为了一些没必要立刻 Stop the world 的任务执行,推荐设置-XX:GuaranteedSafepointInterval=0关闭这个定时
  • 由于 jstack,jmap 和 jstat 等命令,也就是 Signal Dispatcher 线程要处理的大部分命令,都会导致 Stop the world:这种命令都需要采集堆栈信息,所以需要所有线程进入 Safepoint 并暂停。
  • 偏向锁取消(这个不一定会引发整体的 Stop the world,参考 JEP 312: Thread-Local Handshakes):Java 认为,锁大部分情况是没有竞争的(某个同步块大多数情况都不会出现多线程同时竞争锁),所以可以通过偏向来提高性能。即在无竞争时,之前获得锁的线程再次获得锁时,会判断是否偏向锁指向我,那么该线程将不用再次获得锁,直接就可以进入同步块。但是高并发的情况下,偏向锁会经常失效,导致需要取消偏向锁,取消偏向锁的时候,需要 Stop the world,因为要获取每个线程使用锁的状态以及运行状态。
  • Java Instrument 导致的 Agent 加载以及类的重定义:由于涉及到类重定义,需要修改栈上和这个类相关的信息,所以需要 Stop the world。
  • Java Code Cache 相关:当发生 JIT 编译优化或者去优化,需要 OSR 或者 Bailout 或者清理代码缓存的时候,由于需要读取线程执行的方法以及改变线程执行的方法,所以需要 Stop the world
  • GC:这个由于需要每个线程的对象使用信息,以及回收一些对象,释放某些堆内存或者直接内存,所以需要 Stop the world
  • JFR 的一些事件:如果开启了 JFR 的 OldObject 采集,这个是定时采集一些存活时间比较久的对象,所以需要 Stop the world。同时,JFR 在 dump 的时候,由于每个线程都有一个 JFR 事件的 buffer,需要将 buffer 中的事件采集出来,所以需要 Stop the world。

Server端图片导出

最近的工作需要在服务端生成报表图片,Java库生成的图片实在是惨不忍睹,酷炫的还是要看JS😂。解决方案是: 服务数据 + html模板 + headless浏览器。

Java 模块化

JDK 从Java 9开始 在包之上引入了一个新的抽象级别,正式名称为 Java 平台模块系统 (JPMS),简称“模块”。Java 模块是一种打包机制,使您能够将 Java 应用程序或 Java API 打包为单独的 Java 模块。Java 模块被打包为模块化 JAR 文件。Java 模块可以指定它包含哪些 Java 包,这些包应该对使用此模块的其他 Java 模块可见。Java 模块还必须指定完成其工作所需的其他 Java 模块。