线程的结束方式一stop:
stop()会释放所有的锁,并且不会做善后工作,会导致其他线程抢到锁,然后读取到中间数据导致数据不一致;所以stop方法废弃了;
public class TestThread {
@SneakyThrows
public static void main(String[] s){
Thread t1 = new Thread(()->{
while (true){
try {
System.out.println("go on ...");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
TimeUnit.SECONDS.sleep(5);
t1.stop();
}
}
线程的暂停/继续:
暂停的时候是不会释放当前线程所拥有的锁的,假如你没有继续启动resume的话就会导致死锁,所以这两个方法suspend()和resume()废弃了,最好别轻易使用。
public class TestThread {
@SneakyThrows
public static void main(String[] s){
Thread t1 = new Thread(()->{
while (true){
try {
System.out.println("go on ...");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
TimeUnit.SECONDS.sleep(5);
t1.suspend();//暂停
TimeUnit.SECONDS.sleep(3);
t1.resume();//继续
}
}
利用volatile控制线程:
public class TestThread {
private static volatile boolean runFlag = true;
@SneakyThrows
public static void main(String[] s){
Thread t = new Thread(()->{
long i = 0L;
while (runFlag){
i++;
}
System.out.println("run end and i="+i);
//第一次运行 输出:run end and i=3574874025
//第二次运行 输出:run end and i=3587827843
});
t.start();
TimeUnit.SECONDS.sleep(1);
runFlag = false;
}
}
上面的代码是用volatile修饰的变量来判断是否结束线程,是比较优雅的结束线程,但你很难精确的控制线程运行了多少次才结束,所以你只要不依赖线程的中间状态来判断释放结束,volatile还是比较可以的;
利用interrup来结束线程:
public class TestThread {
@SneakyThrows
public static void main(String[] s){
Thread t = new Thread(()->{
while (!Thread.interrupted()){
}
System.out.println("t end !");
});
t.start();
TimeUnit.SECONDS.sleep(1);
t.interrupt();
}
}
Interrupt设置标志位来打断线程跟volatile类似;interrupt更优雅一点,因为在线程sleep,wait,join的时候interrupt可以捕获异常来做进一步处理(比如做中断线程的处理),但是volatile是判断不了的只能等待、死等,不能跳到下一次循环去读取running变量的值;
利用interrupt()和isInterrupted优雅的结束线程
public class TestThread {
@SneakyThrows
public static void main(String[] s){
Thread t = new Thread(()->{
for (;;){
if (Thread.currentThread().isInterrupted()){
System.out.println("Thread is interrupted!");
System.out.println(Thread.currentThread().isInterrupted());
break;
}
}
});
t.start();
TimeUnit.SECONDS.sleep(2);
t.interrupt();
}
}
总结结束线程的方法:
1. 自然结束(能自然结束尽量自然结束)
2. stop() suspend() resume() 等方式结束
3. 通过判断volatile标志来结束
a. 不适合某些场景(比如volatile变量还没同步的时候线程就做了阻塞,则没有办法循环回去)
b. 打断时间不精准,比如一个阻塞集合,容量为1000的时候希望结束线程不要再添加,但是由于volatile同步线程标志位的时间控制的不是很精准,有可能线程还要继续跑一会儿才会停止。
4. 利用interrupt() 和 isInterrupted() 来优雅的控制线程的结束。