集美大学 计算机 郑如滨

教学博客

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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种方法比较保守、安全。

posted on 2017-07-16 21:45  zhrb  阅读(961)  评论(8编辑  收藏  举报