三、💙
Thread的方法💙
(一个线程的run方法执行完毕,就算终止了。此时的终止此处线程,就是要想办法让run尽快执行完毕(正常不会出现run没执行完毕,突然就没了的情况)
(sleep相当于是停一会,不是说停止了)
1.程序猿们手动设置标志位,如
public static voolean isQuit=false;(写成成员变量,不会触发变量捕捉,而是内部类来访问成员变量, 看下面这个图,代码在后面,执行完isQuit=true; 线程就终止了,同时main也走完了。
public class Demo { public static boolean isQuit=false; public static void main(String[] args) throws InterruptedException { int n =0; Thread t=new Thread(()->{ int m =0; while(!isQuit){ System.out.println("hello world"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } },"myThread"); t.start(); while (n<3) { System.out.println("love"); n++; Thread.sleep(1000); } isQuit=true; //手动终止 } }
但是我们来看下面这个图,为什么我这样放进方法里面不可以呢?——这就源于我们lambda表达式的变量捕捉机制~
lambda可以捕获外界变量,这样lambda表达式执行的时机是更靠后的,这就导致,后续真正执行lambda时候,局部变量isQuit是否可能已经被销毁了呢?
这种情况是客观存在的,让lambda去访问一个已经被销毁的变量,很明显是不合适的,lambda引入了变量捕获这样的机制~,lambda去访问一个已经被销毁的变量,但明显是不合适的,lambda引入了变量捕获这样的机制~,lambda内部看起来是直接访问外部的变量,其实本质是把外部变量给复制了一份,到lambda里面(这样就可以解决刚才的生命周期问题了)(但是捕获变量有限制的,要求是be final(如同final,就是一个变量,我们后续没有修改他的操作) or effectively final(事实上的最终值 final修饰)
2.直接用Thread 类,给我们提供了现成标志位,不用手动, 🐶
while(!Thread.currentThread().isInterrupted())
Thread.currentThread():的含义获取当前线程的对象Thread,提供静态方法,currentThread在哪个线程调动这个方法,就能够获取到哪个线程的引用(相当于就是t,但是不可以写t,写t是报错的)
isInterrupted()
对象内部,提供了一个标志位(boolean类型的)
true:结束
false:不结束
我们看上面的图能发现,为啥还会有异常呢?🐹,原因就是一个线程kennel正在运行,也可能处于sleep状态,如果线程sleep的过程中,是否应该把他唤醒你?
当然了,肯定要把他唤醒,但是sleep在唤醒的同时也会自动清除前面设置的标志位,给程序猿们留下操作空间,此时要是想让线程结束,则catch之后加一个break;
sleep唤醒之后,程序猿们一般有以下几种操作方式:
1.立即停下来,立即结束线程
2.忽略终止请求,继续循环(不写break)
3.继续做点别的事情,过一会再结束线程(catch之后执行别的逻辑,最后break;)
public class Demo { public static void main(String[] args) throws InterruptedException { int n =0; Thread t= new Thread(()->{ int m =0; while(!Thread.currentThread().isInterrupted()){ System.out.println("hello world"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); break; } } },"myThread"); t.start(); while (n<3) { System.out.println("love"); n++; Thread.sleep(1000); } t.interrupt(); } }
四、💗
等待线程——join
多个线程是并发执行的,具体的执行过程,都是由操作系统复制调度的!!!,操作系统的调度线程“随机的”(当然,是我们无法确定他的先后顺序)
等待线程就是一种规划线程结束顺序的手段~ A,B两个线程,希望B先结束,A后结束,此时就可以,让A线程调用B.join方法(去等待B)
此时B线程还没结束完,A线程就会进入阻塞状态,相当于给B留下了空间,B执行完毕之后,A再从阻塞状态中恢复回来,并且继续往后执行。,如果A执行到B.join的时候,B已经执行完,那么A就不用阻塞了,直接往下执行即可,如下图,他是等待,先把t这个线程走完了,再去走下面的main.
阻塞->该代码暂时不继续执行(该进程暂时不去cpu参与调度)sleep也能让该线程阻塞,但是是有时间限制的
join是死等,知道你完事,不然他不会开始(不推荐) 产生一个新的join(里面填写时间)最大等待时间。只要我时间到了,不管你来不来,我都走了(更推荐使用,这种时间版本,留有余地。)
可以被interrupt唤醒的等待操作:
1.join
2.sleep
3.wait
需要的自己拿着用呗
public class Demo { public static void main(String[] args) throws InterruptedException { int n =0; Thread t= new Thread(()->{ int m =0; while(m<5){ System.out.println("hello world"); m++; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } },"myThread"); t.start(); t.join(3000); while (n<3) { System.out.println("love"); n++; Thread.sleep(1000); } } }