
一、join() 的使用main方法里面的线程是一个主线程,由于线程的执行是并发执行,所以创建一个新的线程,在新的线程里面计算1234......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 t2load loadadd addsave saveload loadadd addsave save如果每次的并发执行都是按照上面这两种顺序执行的,那么count的就不会出现问题,但是每次的执行顺序都非常随机,不会每次都是上面的这种执行顺序.t1 t2loadloadaddsave addsave就像上面的这个执行顺序,第一次循坏结束之后,count的值应该是2,但是根据上面的这个执行顺序执行之后,count的值却是1.这就是线程安全的问题.三、线程安全的成因与解决思路造成线程安全有以下原因:1.操作系统的调度是随机的(主要原因)2.两个线程针对一个变量进行修改3.修改操作不是原子的4.内存可见性解决线程安全的方法有:1.使用单线程,但是单线程的效率非常低,这个方法就不怎么样2.两个线程分别针对两个变量进行修改,但是这个方法是针对特定的场景使用的3.两个线程只读取数据,不进行修改,这个方法也是针对特定场景的.除了上述的三种方法,还可以使用锁来解决线程安全的问题.锁可以类比为上厕所的时候,厕所里面有人,如果还有其他的人想上厕所,那么这些人就得等厕所里面的人出来之后才能进去上厕所.锁的方法就是把count的三条指令封装起来,这样CPU每次执行这样封装的指令,就不会产生上面的那种情况.