线程中止与volatile

1.使用标志位中止线程

在Java中但愿中止线程,可使用设置标志位的方法,以下例所示: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)方法都要同步。ide

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)的时候都能看到最近刚刚被写入的值。ui

结论:线程

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

参考:code

Effective Javaget

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

相关文章
相关标签/搜索