1.使用标志位停止线程

在Java中希望停止线程,可以使用设置标志位的方法,如下例所示:

class SimpleTask implements Runnable{
private boolean stop = false; public void stop(){
stop = true;
} @Override
public void run() {
while(!stop){ }
System.out.println("quit");
}
} public class StopThreadTest { public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
SimpleTask simpleTask = new SimpleTask();
executor.execute(simpleTask);
executor.shutdown();
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String word = sc.next();
if(word.equals("stop")){
System.out.println("stop the task");
simpleTask.stop();
}else if(word.equals("!"))
break;
}
}
}

然而无法成功停止线程。原因,没有同步,就不能保证后台线程何时“看到”main线程堆stop的值所做的改编。虚拟机将

while(!stop){}
//转化为
if(!stop)
while(true){}

改进,使用同步方法访问stop域。注意:读(getStop)写(stop)方法都要同步。

class SimpleTask implements Runnable{
private boolean stop = false; public synchronized void stop(){
stop = true;
} public synchronized boolean getStop(){
return stop;
} @Override
public void run() {
while(!getStop()){ }
System.out.println("quit");
}
}
public class StopThreadTest { public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
SimpleTask simpleTask = new SimpleTask();
executor.execute(simpleTask);
executor.shutdown();
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String word = sc.next();
if(word.equals("stop")){
System.out.println("stop the task");
simpleTask.stop();
}else if(word.equals("!"))
break;
}
}
}

使用volatile关键字可以获得一个更简洁、性能更好的版本

class SimpleTask implements Runnable{
private volatile boolean stop = false; public void stop(){
stop = true;
} @Override
public void run() {
while(!stop){ }
System.out.println("quit");
}
} public class StopThreadTest { public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
SimpleTask simpleTask = new SimpleTask();
executor.execute(simpleTask);
executor.shutdown();
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String word = sc.next();
if(word.equals("stop")){
System.out.println("stop the task");
simpleTask.stop();
}else if(word.equals("!"))
break;
}
}
}

原因:虽然volatile不执行互斥访问,但它可以保证任何一个线程(比如本例中的main线程)读取该域(stop)的时候都能看到最近刚刚被写入的值。

结论:

  1. 当多个线程共享可变数据的时候,每个读或者写数据的线程都必须执行同步(synchronized)。如果没有同步,就无法保证一个线程所做的修改可以被另一个线程获知。
  2. 如果需要线程之间的交互通信,而不需要互斥,volatile修饰符就是一种可以接收的同步形式。

参考:

Effective Java

2.使用线程的interrupt方法停止线程

原始链接:How can I kill a thread? without using stop();

public class HelloWorld {

    public static void main(String[] args) throws Exception {
Thread thread = new Thread(new Runnable() {
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(5000);
System.out.println("Hello World!");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
thread.start();
System.out.println("press enter to quit");
System.in.read();
thread.interrupt();
}
}

使用这种方法停止线程的好处:Interrupting 可以让sleep()与wait()的线程直接被抛出异常,然后被终止。而不用等待其sleep完才能终止。

但也有不少人对这种方法提出质疑,认为这样终止线程比较危险。

总的来说使用第1种方法比较保守、安全。

线程停止与volatile的更多相关文章

  1. java线程学习之volatile关键字

    volatile变量的主要作用:是使变量在多个线程间可见. 在java中每一个线程都会有一块工作内存区,其中存放着所有线程共享的主内存的变量值的拷贝.当线程执行时,它在自己的工作内存区操作这些变量,为 ...

  2. 注意!你的Thread.Abort方法真的让线程停止了吗?

    大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Threa ...

  3. C# Thread.Abort方法真的让线程停止了吗?

    大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Threa ...

  4. Java如何检查一个线程停止或没有?

    Java如何检查一个线程停止或没有? 解决方法 下面的示例演示如何使用 isAlive()方法检查一个线程是否停止. public class Main { public static void ma ...

  5. EF Core使用SQL调用返回其他类型的查询 ASP.NET Core 2.0 使用NLog实现日志记录 CSS 3D transforms cSharp:use Activator.CreateInstance with an Interface? SqlHelper DBHelper C# Thread.Abort方法真的让线程停止了吗? 注意!你的Thread.Abort方法真

    EF Core使用SQL调用返回其他类型的查询   假设你想要 SQL 本身编写,而不使用 LINQ. 需要运行 SQL 查询中返回实体对象之外的内容. 在 EF Core 中,执行该操作的另一种方法 ...

  6. (一)juc线程高级特性——volatile / CAS算法 / ConcurrentHashMap

    1. volatile 关键字与内存可见性 原文地址: https://www.cnblogs.com/zjfjava/category/979088.html 内存可见性(Memory Visibi ...

  7. Java线程停止interrupt()方法

    程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的.难以发现的错误.在本篇文章中,我们针对这些难题之一:如何中断一个正在运行的线程. 中 ...

  8. Thread的中断机制(interrupt),循环线程停止的方法

    一.中断原理 中断线程 线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个 ...

  9. java多线线程停止正确方法

    //军队线程 //模拟作战双方的行为 public class ArmyRunnable implements Runnable { //volatile保证了线程可以正确的读取其他线程写入的值 // ...

随机推荐

  1. POJ-2240 Arbitrage---判断正环+枚举

    题目链接: https://vjudge.net/problem/POJ-2240 题目大意: 已知n种货币,以及m种货币汇率及方式,问能否通过货币转换,使得财富增加. 思路: 由于这里问的是财富有没 ...

  2. 新手创建Vue项目

    ======================安装vue=============================(参考网址:http://www.bubuko.com/infodetail-21320 ...

  3. js字符串操作总结

    字符方法 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf- ...

  4. Unity中的基础光照

    渲染包含了两大部分:决定一个像素的可见性,决定这个像素上的光照计算. 光照模型就是用于决定在一个像素上进行怎样的光照计算. 一.光源 在实时渲染中我们通常把光源当做一个没有体积的点. 1.1 辐照度 ...

  5. CSS3属性之圆角效果——border-radius属性

    在css3之前,要实现圆角的效果可以通过图片或者用margin属性实现(可以参考这里:http://www.hicss.net/css-practise-of-image-round-box/).实现 ...

  6. [LeetCode] My Calendar II 我的日历之二

    Implement a MyCalendarTwo class to store your events. A new event can be added if adding the event w ...

  7. Python数据类型和数据操作

    python数据类型有:int,float,string,boolean类型.其中string类型是不可变变量,用string定义的变量称为不可变变量,该变量的值不能修改. 下面介绍python中的l ...

  8. Shell自学二(参数传递和数组)

    8.传递参数    1.使用$n来传递参数($0表示文件名)    例子:    echo "执行的文件名:$0";    echo "第一个参数为:$1";  ...

  9. codevs 3061 质子撞击炮②

    提交地址:http://codevs.cn/problem/3016/ 3016 质子撞击炮 II  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 黄金 Gold     题目描 ...

  10. [ZJOI 2015]幻想乡战略游戏

    Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来, ...