面试题:Java中如何停止线程的方法

来源:脚本之家  责任编辑:小易  

有三种方法可以使终止线程。 1. 使用退出标志,使线程正常退出,也就是当run方法完成后线

如何停止线程是Java并发面试中的常见问题,本篇文章将从答题思路到答题细节给出一些参考。

Java中终止线程的方式主要有三种:1、使用stop()方法,已被弃用。原因是:stop()是立即

答题思路: 停止线程的正确方式是使用中断 想停止线程需要停止方,被停止方,被停止方的子方法相互配合 扩展到常见的错误停止线程方法:已被废弃的stop/suspend,无法唤醒阻塞线程的volatile

在《Why are Thread.stop, Thread.suspend and Thread.r

1. 正确方式是中断

调用些方法yield()暂停当前正在执行的线程对象,并执行其他线程

其实从逻辑上也很好理解的,一个线程正在运行,如何让他停止?

创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。创建线程的另一种方法是声明

A. 从外部直接调用该线程的stop方法,直接把线程停下来。

觉得秦俑是用活人烧制的人不知道脑子里到底装的是什么,但凡有点常识的人都知道,在一个活人或者死人身上裹上一层厚厚的泥土之后这个俑的体积会变得很大,而且看起来非常臃肿,比例都不协调了。再说烧制,即使你有办法把封存着尸体的兵马俑做的很逼真很协调,那么烧制也是个大问题,泥土里的肉体在遇到高温以后会抽搐,扭曲,还会膨胀释放气体,这种情况下不等泥土硬化就完全破裂了。怎么会可能烧制成陶俑?而且秦国攻赵白起坑杀40赵军的时候这个罪名是白起一个人背了,这就是说即使秦国再残暴,他也不会让国家背负这个恶名。而作为一国之君的秦始皇更不可能将自己的军队牺牲掉为自己陪葬,他自己也背不起这个恶名。

B. 从外部通过中断通知线程停止,然后切换到被停止的线程,该线程执行一系列逻辑后自己停止。

春晚这个13亿中国人的盛会,全球中国人的年夜饭,向来不避讳,谁火邀请谁来参加。据悉,“洪荒少女”傅园慧的所在单位已经接到了中央电视台发来的函件,傅园慧将有望亮相2017年央视春节晚会。傅园慧所在单位——浙江体育职业技术学院上周接到中央电视台发来的函件,希望学校同意傅园慧参加2017年央视的春节晚会。该校相关负责人也确认了此事:“从单位的角度,在不影响正常训练的情况下是同意她参加春晚的。”但是其父亲表示她目前在北京封闭式训练,女儿担心参加春晚影响训练,希望有不影响她训练的两全办法。最终我们能否在春晚看到她的亮相值得期待!下面就简单的盘点下那些年上过春晚的明星: 第一次登上春晚舞台的体育明星是乒乓

很明显B方法要比A方法好很多,A方法太暴力了,你根本不知道被停止的线程在执行什么任务就直接把他停止了,程序容易出问题;而B方法把线程停止交给线程本身去做,被停止的线程可以在自己的代码中进行一些现场保护或者打印错误日志等方法再停止,更加合理,程序也更具健壮性。

爆米花大家都再熟悉不过了,可爆米花机爆鸡你就没见过了吧,爆米花机子爆出来的鸡长什么样呢?看这个农村大婶是怎么做的。这个农村大婶把一只鸡剁碎,随后放进爆米花机,就摇起来,没一会,只听“嘭”的一声,一股香味扑鼻而来,大家早已在后面排起了长长的队。这种鸡五分钟左右就可以出锅,效率高,时间短,这个农民老伯用的鸡是自己养的,所以生意异常火爆,前来买鸡的人每天都排着长长的队,大家都表示这种鸡即有新鲜感味道也不错,大婶给这种鸡取名为“蹦蹦鸡”。

下面要讲的是线程如何能够响应中断,第一个方法是通过循环不断判断自身是否产生了中断:

李连杰1963年4月26日出生在北京市一个普通的工人家庭,家里有两个姐姐和两个哥哥。但是1965年李连杰的父亲就去世了,所以他一直是在一个单亲的家庭长大。后来在1971年,刚刚入学的李连杰就被教练吴彬看中,进入北京什刹海体校学习武术,开始了他的武术运动员生涯。1979年因伤退出武术界之后,1980年便在导演张鑫炎的邀请下出演动作电影《少林寺》。之后拍摄了三四部电影,因为自导自演的《无敌小子》票房不佳,渐渐淡出演艺圈。很多人不知道的是李连杰虽然出生在北京,但是作为进京工作的工人家庭子女,据说他一直没有获得北京本地户口。后来李连杰就和前妻黄秋燕去了美国发展,并成功拿到了美国绿卡。李连杰因为为人一直

public class Demo1 implements Runnable{ @Override public void run() { int num = 0; while(num <= Integer.MAX_VALUE / 2 && !Thread.currentThread().isInterrupted()){ if(num % 10000 == 0){ System.out.println(num); } num++; } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Demo1()); thread.start(); thread.sleep(1000); thread.interrupt(); } }

在上面的代码中,我们在循环条件中不断判断线程本身是否产生了中断,如果产生了中断就不再打印

还有一个方法是通过java内定的机制响应中断:当线程调用sleep(),wait()方法后进入阻塞后,如果线程在阻塞的过程中被中断了,那么线程会捕获或抛出一个中断异常,我们可以根据这个中断异常去控制线程的停止。具体代码如下:

public class Demo3 implements Runnable { @Override public void run() { int num = 0; try { while(num < Integer.MAX_VALUE / 2){ if(num % 100 == 0){ System.out.println(num); } num++; Thread.sleep(10); } } catch (InterruptedException e) {//捕获中断异常,在本代码中,出现中断异常后将退出循环 e.printStackTrace(); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Demo3()); thread.start(); Thread.sleep(5000); thread.interrupt(); } }

2. 各方配合才能完美停止

在上面的两段代码中已经可以看到,想通过中断停止线程是个需要多方配合。上面已经演示了中断方和被中断方的配合,下面考虑更多的情况:假如要被停止的线程正在执行某个子方法,这个时候该如何处理中断?

有两个办法:第一个是把中断传递给父方法,第二个是重新设置当前线程为中断。

先说第一个例子:在子方法中把中断异常上抛给父方法,然后在父方法中处理中断:

public class Demo4 implements Runnable{ @Override public void run() { try{//在父方法中捕获中断异常 while(true){ System.out.println("go"); throwInterrupt(); } }catch (InterruptedException e) { e.printStackTrace(); System.out.println("检测到中断,保存错误日志"); } } private void throwInterrupt() throws InterruptedException {//把中断上传给父方法 Thread.sleep(2000); } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Demo4()); thread.start(); Thread.sleep(1000); thread.interrupt(); } }

第二个例子:在子方法中捕获中断异常,但是捕获以后当前线程的中断控制位将被清除,父方法执行时将无法感知中断。所以此时在子方法中重新设置中断,这样父方法就可以通过对中断控制位的判断来处理中断:

public class Demo5 implements Runnable{ @Override public void run() { while(true && !Thread.currentThread().isInterrupted()){//每次循环判断中断控制位 System.out.println("go"); throwInterrupt(); } System.out.println("检测到了中断,循环打印退出"); } private void throwInterrupt(){ try { Thread.sleep(2000); } catch (InterruptedException e) { Thread.currentThread().interrupt();//重新设置中断 e.printStackTrace(); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Demo5()); thread.start(); Thread.sleep(1000); thread.interrupt(); } }

讲到这里,正确的停止线程方法已经讲的差不多了,下面我们看一下常见的错误停止线程的例子:

3. 常见错误停止线程例子:

这里介绍两种常见的错误,先说比较好理解的一种,也就是开头所说的,在外部直接把运行中的线程停止掉。这种暴力的方法很有可能造成脏数据。

看下面的例子:

public class Demo6 implements Runnable{ /** * 模拟指挥军队,以一个连队为单位领取武器,一共有5个连队,一个连队10个人 */ @Override public void run() { for(int i = 0; i < 5; i++){ System.out.println("第" + (i + 1) + "个连队开始领取武器"); for(int j = 0; j < 10; j++){ System.out.println("第" + (j + 1) + "个士兵领取武器"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("第" + (i + 1) + "个连队领取武器完毕"); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Demo6()); thread.start(); Thread.sleep(2500); thread.stop(); } }

在上面的例子中,我们模拟军队发放武器,规定一个连为一个单位,每个连有10个人。当我们直接从外部通过stop方法停止武器发放后。很有可能某个连队正处于发放武器的过程中,导致部分士兵没有领到武器。

这就好比在生产环境中,银行以10笔转账为一个单位进行转账,如果线程在转账的中途被突然停止,那么很可能会造成脏数据。

另外一个“常见”错误可能知名度不是太高,就是:通过volatile关键字停止线程。具体来说就是通过volatile关键字定义一个变量,通过判断变量来停止线程。这个方法表面上是没问题的,我们先看这个表面的例子:

public class Demo7 implements Runnable { private static volatile boolean canceled = false; @Override public void run() { int num = 0; while(num <= Integer.MAX_VALUE / 2 && !canceled){ if(num % 100 == 0){ System.out.println(num + "是100的倍数"); } num++; } System.out.println("退出"); } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Demo7()); thread.start(); Thread.sleep(1000); canceled = true; } }

但是这个方法有一个潜在的大漏洞,就是若线程进入了阻塞状态,我们将不能通过修改volatile变量来停止线程,看下面的生产者消费者例子:

/** * 通过生产者消费者模式演示volatile的局限性,volatile不能唤醒已经阻塞的线程 * 生产者生产速度很快,消费者消费速度很慢,通过阻塞队列存储商品 */ public class Demo8 { public static void main(String[] args) throws InterruptedException { ArrayBlockingQueue storage = new ArrayBlockingQueue(10); Producer producer = new Producer(storage); Thread producerThread = new Thread(producer); producerThread.start(); Thread.sleep(1000);//1s足够让生产者把阻塞队列塞满 Consumer consumer = new Consumer(storage); while(consumer.needMoreNums()){ System.out.println(storage.take() + "被消费"); Thread.sleep(100);//让消费者消费慢一点,给生产者生产的时间 } System.out.println("消费者消费完毕"); producer.canceled = true;//让生产者停止生产(实际情况是不行的,因为此时生产者处于阻塞状态,volatile不能唤醒阻塞状态的线程) } } class Producer implements Runnable{ public volatile boolean canceled = false; private BlockingQueue storage; public Producer(BlockingQueue storage) { this.storage = storage; } @Override public void run() { int num = 0; try{ while(num < Integer.MAX_VALUE / 2 && !canceled){ if(num % 100 == 0){ this.storage.put(num); System.out.println(num + "是100的倍数,已经被放入仓库"); } num++; } } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println("生产者停止生产"); } } } class Consumer{ private BlockingQueue storage; public Consumer(BlockingQueue storage) { this.storage = storage; } public boolean needMoreNums(){ return Math.random() < 0.95 ? true : false; } }

上面的例子运行后会发现生产线程一直不能停止,因为他处于阻塞状态,当消费者线程退出后,没有任何东西能唤醒生产者线程。

这种错误用中断就很好解决:

/** * 通过生产者消费者模式演示volatile的局限性,volatile不能唤醒已经阻塞的线程 * 生产者生产速度很快,消费者消费速度很慢,通过阻塞队列存储商品 */ public class Demo8 { public static void main(String[] args) throws InterruptedException { ArrayBlockingQueue storage = new ArrayBlockingQueue(10); Producer producer = new Producer(storage); Thread producerThread = new Thread(producer); producerThread.start(); Thread.sleep(1000);//1s足够让生产者把阻塞队列塞满 Consumer consumer = new Consumer(storage); while(consumer.needMoreNums()){ System.out.println(storage.take() + "被消费"); Thread.sleep(100);//让消费者消费慢一点,给生产者生产的时间 } System.out.println("消费者消费完毕"); producerThread.interrupt(); } } class Producer implements Runnable{ private BlockingQueue storage; public Producer(BlockingQueue storage) { this.storage = storage; } @Override public void run() { int num = 0; try{ while(num < Integer.MAX_VALUE / 2 && !Thread.currentThread().isInterrupted()){ if(num % 100 == 0){ this.storage.put(num); System.out.println(num + "是100的倍数,已经被放入仓库"); } num++; } } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println("生产者停止生产"); } } } class Consumer{ private BlockingQueue storage; public Consumer(BlockingQueue storage) { this.storage = storage; } public boolean needMoreNums(){ return Math.random() < 0.95 ? true : false; } }

4. 扩展

可能你还会问:如何处理不可中断的阻塞?

只能说很遗憾没有一个通用的解决办法,我们需要针对特定的锁或io给出特定的解决方案。对于这些特殊的例子,api一般会给出可以响应中断的操作方法,我们要选用那些特定的方法,没有万能药。

扩展阅读,根据您访问的内容系统为您准备了以下内容,希望对您有帮助。

面试如何停止一个线程

问:如何停止一个线程?

由于平时不怎么写多线程,所以直接说了个interrupt()显然是不对的。那么接下来我们探讨一下java中如何停止一个线程。

Thread.stop()

该方法已经不推荐使用,它不能保证安全的退出线程,这里不讨论。

interrupt()方式

我们先来学习下线程的interrupt()、interrupted()、isInterrupted()方法的区别

interrupt():作用是中断本线程,是实例方法

这里的中断线程,并非真正的把线程终止,而是将“中断标记”设置为true。

在本线程内,中断自身是允许的:将“中断标记”设置成true

其他线程中调用本线程的interrupt(),会通过checkAccess()检查权限,可能抛出SecurityException()异常。

若本线程当前是阻塞状态,调用interrupt()后,它的“中断线程”状态被清除,并收到InterruptException异常

---------------------

本文来自 Androider_Zxg 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/u012545728/article/details/81018231?utm_source=copy

Java中如何停止一个线程

终止线程的三种方法:1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。 2. 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。3. 使用interrupt方法中断线程。 1. 使用退出标志终止线程 当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的。如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。如果想让循环永远运行下去,可以使用while(true){……}来处理。但要想使while循环在某一特定条件下退出,最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。下面给出了一个利用退出标志终止线程的例子。

package chapter2; public class ThreadFlag extends Thread { public volatile boolean exit = false; public void run() { while (!exit); } public static void main(String[] args) throws Exception { ThreadFlag thread = new ThreadFlag(); thread.start(); sleep(5000); // 主线程延迟5秒 thread.exit = true; // 终止线程thread thread.join(); System.out.println("线程退出!"); } }

在上面代码中定义了一个退出标志exit,当exit为true时,while循环退出,exit的默认值为false.在定义exit时,使用了一个Java关键字volatile,这个关键字的目的是使exit同步,也就是说在同一时刻只能由一个线程来修改exit的值, 2. 使用stop方法终止线程 使用stop方法可以强行终止正在运行或挂起的线程。我们可以使用如下的代码来终止线程: thread.stop(); 虽然使用上面的代码可以终止线程,但使用stop方法是很危险的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果,因此,并不推荐使用stop方法来终止线程。 3. 使用interrupt方法终止线程 使用interrupt方法来终端线程可分为两种情况: (1)线程处于阻塞状态,如使用了sleep方法。 (2)使用while(!isInterrupted()){……}来判断线程是否被中断。 在第一种情况下使用interrupt方法,sleep方法将抛出一个InterruptedException例外,而在第二种情况下线程将直接退出。下面的代码演示了在第一种情况下使用interrupt方法。

package chapter2; public class ThreadInterrupt extends Thread { public void run() { try { sleep(50000); // 延迟50秒 } catch (InterruptedException e) { System.out.println(e.getMessage()); } } public static void main(String[] args) throws Exception { Thread thread = new ThreadInterrupt(); thread.start(); System.out.println("在50秒之内按任意键中断线程!"); System.in.read(); thread.interrupt(); thread.join(); System.out.println("线程已经退出!"); } }

上面代码的运行结果如下: 在50秒之内按任意键中断线程! sleep interrupted 线程已经退出! 在调用interrupt方法后, sleep方法抛出异常,然后输出错误信息:sleep interrupted. 注意:在Thread类中有两个方法可以判断线程是否通过interrupt方法被终止。一个是静态的方法interrupted(),一个是非静态的方法isInterrupted(),这两个方法的区别是interrupted用来判断当前线是否被中断,而isInterrupted可以用来判断其他线程是否被中断。因此,while (!isInterrupted())也可以换成while (!Thread.interrupted())。

JAVA面试题 JAVA中创建线程有几种不同的方式

第一种方式:使用Runnable接口创建线程

第二种方式:直接继承Thread类创建对象

使用Runnable接口创建线程

1.可以将CPU,代码和数据分开,形成清晰的模型

2.线程体run()方法所在的类可以从其它类中继承一些有用的属性和方法

3.有利于保持程序的设计风格一致

直接继承Thread类创建对象

1.Thread子类无法再从其它类继承(java语言单继承)。

2.编写简单,run()方法的当前对象就是线程对象,可直接操作。

在实际应用中,几乎都采取第一种方式

java线程如何停止

你实现的有问题吧,

有继承线程类,或实现Runnable吗?

如果没有这样,那你做的想当于在同一个线程里做了一个死循环。

下边是个例子,你参考一下,

点开始过度条在动,点一下暂停,会停下来,再点一下暂停又会动起来。

点stop会停下来,你看一下。

----------------------------------------------------------------

import java.awt.Dimension;

import java.awt.Toolkit;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JProgressBar;

import javax.swing.JToolBar;

import javax.swing.JButton;

import java.awt.event.ActionListener;

import java.awt.event.ActionEvent;

public class Table extends JFrame implements Runnable {

private JProgressBar progress = new JProgressBar();

private boolean start = false;

private boolean pause = false;

private JButton btnStart;

public Table() {

setResizable(false);

getContentPane().setLayout(null);

JToolBar toolBar = new JToolBar();

toolBar.add(new JLabel("state"));

toolBar.add(progress);

toolBar.setFloatable(false);

toolBar.setBounds(0, 247, 454, 21);

getContentPane().add(toolBar);

btnStart = new JButton("start");

btnStart.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

login();

}

});

btnStart.setBounds(12, 10, 91, 21);

getContentPane().add(btnStart);

JButton btnPause = new JButton("Pause");

btnPause.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

pause = !pause;

}

});

btnPause.setBounds(131, 10, 91, 21);

getContentPane().add(btnPause);

JButton btnStop = new JButton("stop");

btnStop.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

start = false;

}

});

btnStop.setBounds(241, 10, 91, 21);

getContentPane().add(btnStop);

setDefaultCloseOperation(EXIT_ON_CLOSE);

setLocationRelativeTo(null);

setSize(460, 300);

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

setLocation((screenSize.width - getWidth()) / 2,

(screenSize.height - getHeight()) / 2);

setVisible(true);

}

public static void main(String[] args) {

new Table();

}

private void login() {

start = true;

btnStart.setEnabled(false);

new Thread(this).start();

}

public void run() {

int value = 0;

while (start) {

try {

if (pause) {

Thread.sleep(50);

continue;

}

progress.setValue(value++);

if (progress.getValue() == progress.getMaximum()) {

break;

}

Thread.sleep(50);

} catch (Exception e) {

}

}

}

}

如何正确停止java中的线程

Thread.stop() //但是已经不建议使用了,抛出异常

建议使用控制语句结束来终止进程

可在run方法中直接return;

  • 本文相关:
  • java string校招面试题过程详解
  • java工程师面试题一面二面整理
  • java面试题string产生了几个对象
  • java面试题 从源码角度分析hashset实现原理
  • java基础面试题整理
  • java中checkbox实现跨页多选的方法
  • 全面解释java中的serialversionuid
  • springboot控制层图片验证码生成
  • eclipse使用maven搭建spring mvc图文教程
  • java并发编程示例(八):处理线程的非受检异常
  • java求解两个非负整数最大公约数算法【循环法与递归法】
  • spring boot2.0整合es5实现文章内容搜索实战
  • mybatis源码浅析(一)开篇
  • spring data jpa实现分页和排序代码实例
  • 深入解析java中threadlocal线程类的作用和用法
  • 面试如何停止一个线程
  • Java中如何停止一个线程
  • JAVA面试题 JAVA中创建线程有几种不同的方式
  • java线程如何停止
  • 如何正确停止java中的线程
  • 如何停止一个Java线程
  • Java中如何正确而优雅的终止运行中的线程
  • 如何停止java线程
  • 怎样在java中关闭多线程其中一个线程?让其他线程还正常运行?
  • 今天的笔试题,java中启动线程3种方法?不是只有star()吗?
  • 免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved