黑马程序员:Java基础 | 您所在的位置:网站首页 › 进程关闭线程会结束吗 › 黑马程序员:Java基础 |
-------
Java EE培训、
java培训、期待与您交流! ----------
1.概念
线程启动了,做完该做的事情,但是它还是会占用系统资源,那么我们该如何停止呢? 我们知道Java中Thread里面有一个方法叫做stop方法,可是,stop方法已经过时。 那么,如何停止线程?只有一种,run方法结束。 开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。 我们先来举个例子: class StopThread implements Runnable{private Boolean flag = true;public void run(){while(flag){System.out.println(Thread.currentThread().getName()+"---run");}}public void changeFlag(){flag = false;}}public class StopThreadDemo { public static void main(String[] args) { StopThread sThread = new StopThread(); new Thread(sThread).start(); new Thread(sThread).start(); int num = 0; while(true){ if(num++ == 60){ sThread.changeFlag(); break; } System.out.println(Thread.currentThread().getName()+"++++++"+num); } System.out.println("Over"); }} 我们来看一下运行结果: 只见这哥们一顿运行,到了num==60的时候程序调用了changeFlag()结束了所有线程。 有一种特殊情况,这种情况程序停不下来,那就是使用了synchronized的同步锁。 我们先来看一下代码: class StopThread implements Runnable{private Boolean flag = true;public synchronized void run(){while(flag){try {wait();} catch (InterruptedException e) {e.printStackTrace();System.out.println(Thread.currentThread().getName()+"...Exception");}System.out.println(Thread.currentThread().getName()+"---run");}}public void changeFlag(){flag = false;}}public class StopThreadDemo { public static void main(String[] args) { StopThread sThread = new StopThread(); new Thread(sThread).start(); new Thread(sThread).start(); int num = 0; while(true){ if(num++ == 60){ sThread.changeFlag(); break; } System.out.println(Thread.currentThread().getName()+"++++++"+num); } System.out.println("Over"); }} 接下来,我们来运行一下: 可以看到,我们的程序只有main线程在输出,而其他两个线程则没有动静,而且,注意图的右上角,红色的小方块证明了这个程序还没有结束。这是为什么呢? 我们回顾一下代码: 我们的flag默认为true,当线程进入synchronized同步锁中判断flag就会直接被位于上面的wait()方法直接叫停,也就是进入冻结状态,同时释放了CPU运行权。这是另一个线程也来了,同样被wait()方法叫停。这两个方法一旦被叫停就无法读取到位于wait()下面的标记,也就无法终止线程了。 我们这样总结: 当线程处于冻结状态时就不会读取到标记,那么线程就不会结束。 那么该如何解决这个问题呢? 在Java的Thread中提供了一种中断线程的方法——interrupt,需要注意的是这个中断不是停止线程,能停止线程的只有stop方法。 * 如果线程在调用Object 类的wait()、wait(long) 或wait(long, int) 方法,或者该类的join()、join(long)、join(long, int)、sleep(long) 或sleep(long, int) 方法过程中受阻,则其中断状态将被清除 interrupt方法的意思就是强制清除线程的冻结状态,即强制唤醒。但是会将收到一个InterruptedException异常。 我们来修改一下代码: class StopThread implements Runnable{private Boolean flag = true;public synchronized void run(){while(flag){try {wait();} catch (InterruptedException e) {e.printStackTrace();System.out.println(Thread.currentThread().getName()+"...Exception");}System.out.println(Thread.currentThread().getName()+"---run");}}public void changeFlag(){flag = false;}}public class StopThreadDemo { public static void main(String[] args) { StopThread sThread = new StopThread(); Thread t1 = new Thread(sThread); t1.start(); new Thread(sThread).start(); int num = 0; while(true){ if(num++ == 60){ //sThread.changeFlag(); t1.interrupt(); break; } System.out.println(Thread.currentThread().getName()+"++++++"+num); } System.out.println("Over"); }} 然后我们运行一下: 注意图中,线程没有终止,而且接收到了异常。为什么没有终止?因为t1被强制唤醒以后又去争CPU执行权时,经过wait()方法时,又一次冻结在那里。同理,另一条线程也这样修改。 这时,我们离结束线程不远了,只要发生了异常我们不妨操作标记来结束线程: class StopThread implements Runnable{private Boolean flag = true;public synchronized void run(){while(flag){try {wait();} catch (InterruptedException e) {e.printStackTrace();System.out.println(Thread.currentThread().getName()+"...Exception");flag = false;}System.out.println(Thread.currentThread().getName()+"---run");}}public void changeFlag(){flag = false;}}public class StopThreadDemo { public static void main(String[] args) { StopThread sThread = new StopThread(); Thread t1 = new Thread(sThread); t1.start(); Thread t2 = new Thread(sThread); t2.start(); int num = 0; while(true){ if(num++ == 60){ //sThread.changeFlag(); t1.interrupt(); t2.interrupt(); break; } System.out.println(Thread.currentThread().getName()+"++++++"+num); } System.out.println("Over"); }} 运行结果如下:我们可以看到,线程异常一样是被输出,但是注意右上角,小方块呈灰色,证明此时程序已经停止运行,也就是说,我们已经将t1,t2两个线程成功的终止掉了。 2.守护线程Java中提供了一种方法——setDaemon() setDaemon()将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。 守护线程可以理解为后台线程。 该方法必须在启动线程前调用。 该方法首先调用该线程的 checkAccess 方法,且不带任何参数。这可能抛出 SecurityException(在当前线程中)。 接下来我们看一下示例: class DaemonThread implements Runnable {private Boolean flag = true;public void run() {while (flag) {System.out.println(Thread.currentThread().getName() + "---run");}} public void changeFlag() {flag = false;}} public class DaemonDemo {public static void main(String[] args) {StopThread sThread = new StopThread(); Thread t1 = new Thread(sThread);Thread t2 = new Thread(sThread); t1.setDaemon(true);t2.setDaemon(true);t1.start();t2.start(); int num = 0;while (true) {if (num++ == 60) {break;}System.out.println(Thread.currentThread().getName() + "++++++" + num);}System.out.println("Over");}} 运行结果是main方法做完了应有的工作,而此时程序关闭。 3.Join()方法前面Interrupt()方法中我们见到过join()方法,join()是什么呢? 接下来我们来看一下join()方法: 在JDK中是这么说的:等待该线程终止。 我们不妨先来看段代码: class Join implements Runnable{public void run(){for(int i = 0;iSystem.out.println(Thread.currentThread().getName()+"---"+i);}}}public class JoinDemo { public static void main(String[] args) throws InterruptedException {Join j = new Join();Thread t1 = new Thread(j);Thread t2 = new Thread(j); t1.start();t1.join(); //join是抢夺CPU执行权t2.start(); for(int i=0;iSystem.out.println("main______"+i);}System.out.println("Over!!!");}} 运行结果:通常情况下,我们的t1,t2,main线程都是交叉运行,输出结果的。但是,当我们添加join()方法后,如上面的代码,这个程序输出的顺序就会是这样的: 1.先让t1全部执行完。 2.再让t2和main线程交替运行。 3.执行完毕,最后关闭程序。 我们就可以理解了,join()方法是一个让本线程执行完,再让其他线程执行的方法。 可是接下来我们这样改: t1.start();t2.start();t1.join(); 我把join()放到了t2.start()后面去,执行结果如下:这又是怎么回事呢? 当A线程执行到了B线程的.join()方法时,A就会等待,等B线程都执行完,A才会执行。 join可以用来临时加入线程执行。 但是当A线程启动,B线程也会启动,但是当主线程碰到A线程的join方法时,主线程就会进入等待状态,而此时A,B线程都在运行状态,那么这时A,B线程就会交替执行,执行完后主线程就会执行。但是,此时的A,B线程并没有消亡,而是处于挂起状态,当主线程执行完毕后才会一起结束,此时,程序结束。 4.优先级&yield方法优先级代表抢资源的频率。 优先级有10级 其中1,5,10级为最明显。 static int MAX_PRIORITY 线程可以具有的最高优先级。 static int MIN_PRIORITY 线程可以具有的最低优先级。 static int NORM_PRIORITY 分配给线程的默认优先级。 |
CopyRight 2018-2019 实验室设备网 版权所有 |