01. 理解 Java 程序运行过程
- java 程序,都是通过 java 命令来运行,实际上,java 命令是启动一个 jvm 过程;jvm 就是 java 虚拟机,jvm 翻译 java 字节码,找到 main 入口,启动 java 线程,从 main 入口,执行 java 程序;通常执行 main 的 java 线程是 main 线程。
- mian 线程执行 java 代码过程中,可能会遇到创立新的线程状况,新创建的线程启动后,和 main 线程并行执行。即便 main 线程退出后,其余创立的线程可能还在运行。
程序运行的实质
- 不论是什么语言的程序,最终都是转换成为机器 010101… 码执行,于是所有程序都能够形象成执行者和工作清单,执行者最终体现在硬件上,最常见的是 CPU,通用是处理器,在软件程序语言层面,执行者就是常说的过程 / 线程。另外一个是工作清单,执行者要工作,必须有一份工作清单,程序代码能够看作是工作清单,是人和机器交换的语言。人要驱动机器干活,必须说机器能听懂的语言,这就是程序语言。
- 一份代码,为什么会呈现多线程问题。打个比方,一份代码好比一份菜单做菜过程,假如要做 10 盘同样的菜,为了快,要 10 集体同时炒菜;设想一下,10 集体同时用一个锅,炒进去的菜能吃吗。这个菜单做菜步骤就是一份代码,10 个厨师同时炒菜就是 10 个线程并发,按理说并发也没问题,然而,因为共享一个锅,问题就呈现了。这就是多线程问题。
多线程问题例子 - 计算固定字符串的 md5 值
public class Test {
private static MessageDigest digest;
public static void main(String[] args) throws Exception {
try {digest = MessageDigest.getInstance("md5");
} catch (Exception e) {e.printStackTrace();
}
calcMd5();
for (int i = 0; i < 10; i++) {new Thread(() -> {calcMd5();
}).start();}
}
private static void calcMd5() {
String str = "test";
byte[] res = digest.digest(str.getBytes(Charset.forName("utf-8")));
StringBuilder sb = new StringBuilder();
for (byte b : res) {sb.append(String.format("%02x", b));
}
System.out.println(Thread.currentThread().getName() + ":" + sb.toString());
}
}
test 的 md5 值是 098f6bcd4621d373cade4e832627b4f6,
但上述代码,多线程执行,有的线程计算结果有问题,一次执行后果如下