Java多线程通俗易懂解读
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个线程并发,按理说并发也没问题,但是,因为共享一个锅,问题就出现了。这就是多线程问题。
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,
但上述代码,多线程执行,有的线程计算结果有问题,一次执行结果如下
【Java多线程通俗易懂解读】
文章图片
多线程并发问题解决 解决10个厨师同时用一口锅的问题,有如下方法
- 每个厨师自己准备锅,即用线程的局部变量。
public class Test {public static void main(String[] args) throws Exception {
MessageDigest digest;
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";
MessageDigest digest;
try {
digest = MessageDigest.getInstance("md5");
} catch (Exception e) {
e.printStackTrace();
return;
}
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());
}
}
- 还是每个厨师一口锅,但这个锅不是厨师的,是饭馆提供的,即ThreadLocal
- 共用一口锅也可以,但确保每次只有一个厨师再用,他用完了再到下一个,即用锁lock
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 爱就是希望你好好活着
- 昨夜小楼听风
- 知识
- 死结。
- 我从来不做坏事
- 烦恼和幸福
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- 事件代理