☰
多线程基础
2026/10/4 3:09:25 网站建设 项目流程

一、join() 的使用

main方法里面的线程是一个主线程,由于线程的执行是并发执行,所以创建一个新的线程,在新的线程里面计算1+2+3+4+......+1000的值并且在主线程中输出,直接运行新的线程,在主线程里面打印的,获取到的值是不会符合我们的预期的.在这个时候我们就可以在主线程中使用join()这个方法,在主线程中使用,就是主线程要等新线程执行完毕之后才执行输出的代码,这样我们就可以得到想要的值.如果新的线程里面出现了Bug,那么主线程就会一直等下去,造成死等.所以我们可以在join()里面传入参数,传入一个我们认为最大应该等多久,如果超过这个时间,新线程还没有执行完毕,那么主线程就不会在等了,会直接执行后面的代码.


二、线程安全问题

由于线程与线程之间资源是共享的,所以可能会造成两个线程在修改同一个数据,这样会有线程安全的问题.例如以下代码:

public class Demon7 {
private static int count = 0;

public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for(int i = 0; i < 50000; i++) {
count++;
}
});
Thread t2 = new Thread(() -> {
for(int i = 0; i < 50000; i++) {
count++;
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("count =" + " " +count);
}
}

这样的代码每次的输出结果都不一样,就是因为出现了线程安全的问题.由于CPU执行指令的时候是一条一条的指令去执行.count++这个代码的指令就是load,add,save三条指令,CPU每次是一条一条的执行,而上面的代码有两个线程,线程是并发的执行,t1线程执行的同时,t2线程也会执行.

t1 t2 t1 t2
load load

add add

save save

load load

add add

save save

如果每次的并发执行都是按照上面这两种顺序执行的,那么count的就不会出现问题,但是每次的执行顺序都非常随机,不会每次都是上面的这种执行顺序.

t1 t2

load
load
add
save add
save

就像上面的这个执行顺序,第一次循坏结束之后,count的值应该是2,但是根据上面的这个执行顺序执行之后,count的值却是1.这就是线程安全的问题.


三、线程安全的成因与解决思路

造成线程安全有以下原因:
1.操作系统的调度是随机的(主要原因)
2.两个线程针对一个变量进行修改
3.修改操作不是原子的
4.内存可见性

解决线程安全的方法有:
1.使用单线程,但是单线程的效率非常低,这个方法就不怎么样
2.两个线程分别针对两个变量进行修改,但是这个方法是针对特定的场景使用的
3.两个线程只读取数据,不进行修改,这个方法也是针对特定场景的.

除了上述的三种方法,还可以使用锁来解决线程安全的问题.锁可以类比为上厕所的时候,厕所里面有人,如果还有其他的人想上厕所,那么这些人就得等厕所里面的人出来之后才能进去上厕所.锁的方法就是把count++的三条指令封装起来,这样CPU每次执行这样封装的指令,就不会产生上面的那种情况.

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询