System.out调用println会自动调用flush的,所以你加不加flush效果一样。 https://docs.oracle.com/javase/8/docs/api/ flush的文档里有说明,并没有说flush会直接输出到设备,而是说把当前缓存信息输出到底层流。这种描述很暧昧,首先我们知道很多设备都有缓存,比如硬盘,cpu,显卡,网卡,声卡等等,都有缓存,那么好了,flush文档里所说的缓存其实是指java程序里的流管道缓存,底层流就是指系统设备的缓存。 你可以参考以下帖子的数据流的基本概念的输出流章节 https://juejin.im/entry/59291f1a44d9040064213c02 插图里的程序和设备之间有条管道,print的时候只是把信息往管道里送,管道满了才会往设备送,flush是立刻把管道的信息往设备送。这里往设备送并不代表信息马上输出,而是送到了设备的缓存,至于缓存的信息何时输出,那就不是jvm能管辖的了,是操作系统调度的。 所以主线程print,flush,只是把信息送到了设备的标准输出缓存,然后程序继续往下执行,抛出异常,jvm的print把异常信息送到了设备标准错误缓存,至于系统究竟会先从标准输出缓存取信息打印还是先从标准错误缓存取信息打印,就无法预知了。
多线程日志打印跟程序执行不一定保持一致的,会出现程序已经执行但是日志还没打印的情况,打印日志也是一个线程
首先,你要知道,系统标准输出设备属于共有系统资源 其次,你要知道,除了你的主线程,jvm内部还有其他的线程也在运行,比如垃圾回收线程等等 再次,你要知道,系统输出是有缓存的,你输出的信息系统会先保存到缓存中,缓存满了再输出 如果你想让输出缓存里的内容立刻输出到控制台,你可能调用System.out.flush() 明白了以上 那就知道,你的main线程和jvm线程(捕获异常打印)都要打印,都需要抢占系统标准输出设备(也就是获得系统资源锁),输出后信息只是保存在输出缓存,并没有马上输出到控制台,所以哪个线程抢到系统标准输出设备锁,不由你控制,所以输出缓存的信息也就不可控,不能按顺序保存,所以输出结果就会错乱
你没看明白或者是忽略输出缓存这部分内容 来具体分析打印操作的步骤 主线程:System.out.print->把信息写入标准输出缓存(如果缓存满了则阻塞,等待缓存内容输出到设备)->获取输出设备(也就是控制台)锁->缓存信息输出到设备 jvm异常打印线程:System.err.print->把信息写入标准错误缓存(如果缓存满了则阻塞,等待缓存内容输出到设备)->获取输出设备(也就是控制台)锁->缓存信息输出到设备 主线程确实是先执行person的打印,然后才抛出异常,jvm线程才开始打印异常信息的,也就是jvm打印发生在主线程打印之后,但是因为有输出缓存,信息并没有马上打印到控制台,在主线程的输出缓存信息没有完全打印到设备之前,jvm线程是有机会抢占到输出设备的,所以就可能乱序 而如果你主线程打印是加了等待0.01s,这个时间很有可能足够主线程的输出缓存信息打印到输出设备,而上面也说了,jvm打印发生在主线程之后,jvm打印的时候主线程的缓存信息已经输出完了,也就是jvm抢到抢不到输出设备锁都不影响结果了,所以也就不乱序了。
[quote=引用 3 楼 API工具助手 的回复:] 多线程日志打印跟程序执行不一定保持一致的,会出现程序已经执行但是日志还没打印的情况,打印日志也是一个线程
int a = 0/0
50,503
社区成员
85,598
社区内容
加载中
试试用AI创作助手写篇文章吧