一、错误的方法——stop()方法
在1.0版本的jdk中,提供了一个stop方法来停止线程,但是这个方法现在已经被废弃了,因为使用这个方法停止线程,将会使线程戛然而止,我们甚至不知道程序执行到了哪里,资源是否已经释放,会出现一些不可预料的结果。
使用stop()方法停止线程实例:
定义一个线程类YieldRunnable.java
public class YieldRunnable implements Runnable{
public volatile boolean isRunning = true;
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + "开始执行!");
while(isRunning) {
for(int i = 1; i < 6; i++) {
System.out.println(name + "执行了[" + i + "]次");
//注意,yield是静态方法
Thread.yield();
}
}
System.out.println(name + "执行结束!");
}
}
接下来是main方法
public static void main(String[] args) {
System.out.println("主线程开始执行!");
YieldRunnable runnable = new YieldRunnable();
Thread thread = new Thread(runnable, "线程1");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.stop();
System.out.println("主线程执行结束!");
}
截取部分执行结果片段:
……
线程1执行了[1]次
线程1执行了[2]次
线程1执行了[3]次
线程1执行了[4]次
线程1执行了[5]次
线程1执行了[1]次线程1执行了[1]次主线程执行结束!
从执行结果可以看出,在调用了stop方法之后,线程中的循环语句还没有执行结束线程就戛然而止了,甚至连最后执行结束的输出都没有打印出来,我们甚至不知道程序执行到哪里了,所以stop()方法是不推荐使用的。
二、正确的方法——使用中断信号
所谓使用中断信号,就是定义一个布尔型的标志位,用于标识线程是否继续执行,线程不定期检查该标志位,当需要将线程停止时,将标志位修改为中断,那么线程就可以被正确停止了。
使用中断信号停止线程实例:
YieldRunnable.java与上例相同,不做修改,写一个main方法
public static void main(String[] args) {
System.out.println("主线程开始执行!");
YieldRunnable runnable = new YieldRunnable();
Thread thread = new Thread(runnable, "线程1");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runnable.isRunning = false;
System.out.println("主线程执行结束!");
}
上面的程序将YieldRunnable类中的isRunning设为中断信号,刚开始主线程运行,启动了子线程,之后主线程将子线程的中断信号设为false,子线程读取到中断信号之后就结束线程。
运行结果:
……
线程1执行了[4]次
线程1执行了[5]次
线程1执行了[1]次
线程1执行了[2]次
线程1执行了[3]次
线程1执行了[4]次
线程1执行了[5]次
主线程执行结束!
线程1执行结束!
由运行结果可以发现,子线程正确执行了所有的循环,并打印退出信息正确退出了。
三、另一种值得推敲的方法,interrupt()方法
public class YieldRunnable implements Runnable{
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + "开始执行!");
while(true) {
for(int i = 1; i < 6; i++) {
System.out.println(name + "执行了[" + i + "]次");
//注意,yield是静态方法
Thread.yield();
}
long time = System.currentTimeMillis();
while(System.currentTimeMillis() - time < 1000) {
/*
* 使用while循环模拟 sleep 方法,这里不要使用sleep,具体原因下面再说
*/
}
}
}
}
再写一个main方法
public static void main(String[] args) {
System.out.println("主线程开始执行!");
YieldRunnable runnable = new YieldRunnable();
Thread thread = new Thread(runnable, "线程1");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
System.out.println("主线程执行结束!");
}
运行之后会发现,虽然执行了interrupt()方法,但是子线程并没有停下来,反而是一直执行下去,由此可以得知,interrupt()方法单独使用不能停止线程。那该如何使用interrupt()方法让它能够来停止线程呢?查阅了jdk之后,我们发现线程保有一个状态叫做中断状态,在调用interrupt()之后,线程的中断状态为true,Java提供两种方法获取线程的中断状态:
public static boolean interrupted();
public boolean isInterrupted()
其中,interrupted()方法是静态的,同时调用了interrupted()方法之后线程的中断状态由该方法清除,换句话说,如果连续两次调用该方法,则第二次调用将返回 false。isInterrupted()方法则不会清除线程的中断状态。
public class YieldRunnable implements Runnable{
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + "开始执行!");
while(!Thread.currentThread().isInterrupted()) {
for(int i = 1; i < 6; i++) {
System.out.println(name + "执行了[" + i + "]次");
//注意,yield是静态方法
Thread.yield();
}
long time = System.currentTimeMillis();
while(System.currentTimeMillis() - time < 1000) {
/*
* 使用while循环模拟 sleep 方法,这里不要使用sleep,具体原因下面再说
*/
}
}
System.out.println(name + "执行结束!");
}
}
执行结果:
线程1开始执行!
线程1执行了[1]次
线程1执行了[2]次
线程1执行了[3]次
线程1执行了[4]次
线程1执行了[5]次
主线程执行结束!
线程1执行结束!
public class YieldRunnable implements Runnable{
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + "开始执行!");
while(!Thread.currentThread().isInterrupted()) {
for(int i = 1; i < 6; i++) {
System.out.println(name + "执行了[" + i + "]次");
//注意,yield是静态方法
Thread.yield();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name + "执行结束!");
}
}
执行结果:
线程1开始执行!
线程1执行了[1]次
线程1执行了[2]次
线程1执行了[3]次
线程1执行了[4]次
线程1执行了[5]次
线程1执行了[1]次java.lang.InterruptedException: sleep interrupted
主线程执行结束!
线程1执行了[2]次
线程1执行了[3]次
……
public class YieldRunnable implements Runnable{
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + "开始执行!");
while(!Thread.currentThread().isInterrupted()) {
for(int i = 1; i < 6; i++) {
System.out.println(name + "执行了[" + i + "]次");
//注意,yield是静态方法
Thread.yield();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.println(name + "执行结束!");
}
}
运行结果:
线程1开始执行!
线程1执行了[1]次
线程1执行了[2]次
线程1执行了[3]次
线程1执行了[4]次
线程1执行了[5]次
主线程执行结束!
线程1执行结束!