java 如何杀死java上的线程?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16202744/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to kill a thread on java?
提问by Damiii
I'm with a headache on killing a thread with java ... I saw a lot of topics on stackoverflow and i didnt get them working on my code ... Can someone explain me how am i able to kill a thread without using deprecated function (like stop) and in a safe way please ( also my thread is running a socket: DatagramSocket).
我对用 java 杀死线程感到头疼......我在stackoverflow上看到了很多主题,但我没有让它们处理我的代码......有人可以解释我如何在不使用已弃用的情况下杀死线程函数(如停止)并以安全的方式(我的线程正在运行一个套接字:DatagramSocket)。
Class p2p_app->
类 p2p_app->
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
//import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class p2p_app {
private String ip;
private Integer porta;
private LinkedList<Vizinho> vizinhos;
private String pathSharedFolder;
private String pathBootStrap;
private int exit;
//private Thread send;
//private Thread receive;
private UDPreceive udpR;
public p2p_app(String args[]) throws IOException {
this.ip = InetAddress.getLocalHost().getHostAddress();
this.vizinhos = new LinkedList<Vizinho>();
this.exit = 0;
//this.send=null;
//this.receive=null;
this.udpR=null;
if(args.length==2){
this.pathSharedFolder=args[0];
this.pathBootStrap=args[1];
System.out.println(pathSharedFolder);
System.out.println(pathBootStrap);
}
else{
this.pathSharedFolder="./";
this.pathBootStrap="./p2p_bootstrap.conf";
System.out.println(pathSharedFolder);
System.out.println(pathBootStrap);
}
readFile(this.pathBootStrap);
createSharedFolder(this.pathSharedFolder);
}
public void assign(String tipo,String info) //tratar o file bootstrap.conf
{
Tipos currentTipos = Tipos.valueOf(tipo.toUpperCase());
switch(currentTipos){
case PATH: if(this.pathSharedFolder==null)
this.pathSharedFolder = info;
break;
case PORTA: this.porta = Integer.parseInt(info);
break;
case IP: StringTokenizer st = new StringTokenizer(info,":");
st.nextElement();
String[] tokens = info.split(":");
Vizinho s = new Vizinho(tokens[0],Integer.parseInt(tokens[1]));
this.vizinhos.add(s);
break;
default:
break;
}
}
public void trataLine(String line){
Pattern p = Pattern.compile("[\w\./:]+");
Matcher m = p.matcher(line);
String tipo = "";
while(m.find()){
if(tipo.compareTo("")==0)
tipo = m.group();
else assign(tipo,m.group());
}
}
public void readFile(String path) throws IOException{ //modifiquei este codigo para ver se existe ou nao o ficheiro bootstrap (VASCO)
String line;
Pattern p = Pattern.compile("\$");
File f = new File(path);
if(f.exists()){
BufferedReader br;
br = new BufferedReader(new FileReader(path));
while ((line = br.readLine()) != null) {
Matcher m = p.matcher(line);
if(m.find() == true)
trataLine(line);
}
br.close();
}
else{
System.out.println("FILE :: BOOTSTRAP.CONF : Doesn't exist.");
}
}
public void createSharedFolder(String path) {
if(!(new File(path).exists()))
new File(path).mkdir();
}
public enum Tipos {
PATH,
PORTA,
T1,
T2,
T3,
R,
M,
K,
IP
}
public String getIp(){
return this.ip;
}
public Integer getPorta(){
return this.porta;
}
public int getExit(){
return this.exit;
}
public void setExit(int exit){
this.exit = exit;
}
public LinkedList<Vizinho> getVizinhos(){
LinkedList<Vizinho> aux = new LinkedList<Vizinho>();
for(Vizinho c : this.vizinhos) aux.add(c);
return aux;
}
public String toString(){
StringBuilder s = new StringBuilder();
s.append("IP:"+this.ip + "\n");
s.append("Porta:"+ this.porta +"\n");
s.append("Directory:" + this.pathSharedFolder + "\n");
s.append("-----Vizinhos-----");
for(Vizinho c : this.vizinhos)
s.append(c.toString());
return s.toString();
}
public void initThreads(p2p_app p2p){
//UDPreceive udpR = new UDPreceive(p2p);
this.udpR = new UDPreceive(p2p);
//UDPsend udpS = new UDPsend(p2p);
//this.receive = new Thread(udpR);
Thread t = new Thread(udpR);
//this.send = new Thread(udpS);
t.start();
//this.receive.start();
//this.send.start();
}
@SuppressWarnings("deprecation")
public void stopThreads(){
this.udpR.stopRun();
//this.receive.interrupt();
//this.receive.stop();
//this.receive.toString();
//this.send.interrupt();
//this.send.toString();
}
public void menu(){
System.out.println("1:Hello");
System.out.println("2:Vasco");
System.out.println("3:Exit");
}
public int choiceMenu(int i){
int numRowsInConsole = 60;
final String ESC = "3[";
switch(i){
case 1:
System.out.println("FUNCIONOU HELLO");
System.out.print(ESC + "2J");
/*for (int ii=0; ii<numRowsInConsole; ii++) {
// scroll down one line
System.out.println("");
}*/
break;
case 2:
System.out.println("FUNCIONOU VASCO");
System.out.print(ESC + "2J");
break;
case 3:
i=-1;
System.out.print(ESC + "2J");
break;
default:
}
return i;
}
public static void main(String[] args) throws IOException {
int i;
p2p_app p2p = new p2p_app(args);
//p2p.initThreads(p2p);
System.out.println(p2p.toString());
Scanner sc = new Scanner(System.in);
while(p2p.getExit() != -1){
p2p.menu();
i = sc.nextInt();
p2p.setExit(p2p.choiceMenu(i));
System.out.println(p2p.getExit());
}
System.out.println("Woot woot!");
//p2p.stopThreads();
}
}
Classe UDPreceive->
类 UDPreceive->
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UDPreceive implements Runnable {
private p2p_app p2p;
private DatagramPacket p;
public volatile boolean stopThread = true;
public void stopRun(){
this.stopThread=false;
}
public UDPreceive(p2p_app p2p){
this.p2p = p2p;
}
/**
* @param args
*/
public void run(){
DatagramSocket socket=null;
UDPpacket udp;
byte[] x = new byte[1000];
try{
socket = new DatagramSocket(8734);
socket.setBroadcast(true);
//while(this.p2p.getExit() !=-1){
while(stopThread){
p = new DatagramPacket(x,x.length);
socket.receive(p);
udp = new UDPpacket(p,this.p2p);
udp.tostring();
//udp.setDatagramPacket(p);
//String d = new String(p.getData());
//System.out.println("Mensagem enviada por mim: "+d);
}
//Thread.sleep(100);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
how am i able to kill a thread on my main function in p2p_app class ? i create a thread for my UDPreceiver class :F
我如何能够杀死 p2p_app 类中主函数上的线程?我为我的 UDPreceiver 类创建了一个线程:F
回答by KyleM
For the most part, the only "safe" way to kill a Thread is to code the Thread in such a way that it can receive a signal to stop. For example, use a boolean variable called shouldQuit
and have the Thread periodically check that variable, quitting if it's true. You could also do stuff like interrupt the Thread, but that isn't always safe.
在大多数情况下,杀死线程的唯一“安全”方法是以可以接收停止信号的方式对线程进行编码。例如,使用一个布尔变量,shouldQuit
并让线程定期检查该变量,如果为真则退出。您也可以执行诸如中断线程之类的操作,但这并不总是安全的。
回答by user2317441
package test;
/**
* simple thread class that prints '.' to the screen
* @author Manex
*
*/
public class ThreadTest extends Thread {
private boolean running = true ;
public void run(){
try{
while(running){
//do something here
System.out.print(".");
sleep(1000);
}
}catch(InterruptedException e){
System.out.println(e.getMessage());
}
System.out.println("Stopped");
}
/**
* a method to stop the thread
*/
public void stopRunning(){
this.running = false ;
}
public static void main(String[] args){
//creating threads
ThreadTest[] t = new ThreadTest[2] ;
t[0] = new ThreadTest() ;
t[1] = new ThreadTest() ;
//starting threads
for(ThreadTest e : t){
e.start();
}
try {
//the main thread does something
int x = 5 ;
while(x > 0){
sleep(1000) ;
x -= 1 ;
}
//the main thread ended
System.out.println("main thread ends here");
} catch (InterruptedException e) {
e.printStackTrace();
}
//before exiting - stop all threads
for(ThreadTest e : t){
e.stopRunning();
}
}
}
if ur planing on stopping threads that you have created , for any reason , you should keep tracking them and hold a reference to each thread you might want to stop instead of waiting for it to done execution all by itself (the run method simply ends). in this simple test , if you remove the stop loop , the threads will continue printing and never stop untill you stop them manually , even after main thread termination.. i hope this was usefull..
如果您计划停止您创建的线程,出于任何原因,您应该继续跟踪它们并保存对您可能想要停止的每个线程的引用,而不是等待它自己完成执行(run 方法只是结束) . 在这个简单的测试中,如果您删除停止循环,线程将继续打印并且永远不会停止,直到您手动停止它们,即使在主线程终止之后..我希望这很有用..
回答by Will
The reason your UDPReceive thread is not stopping is you are using the blocking method DatagramSocket.receive()in your UDPReceive.run() while loop. The JavaDocs for this method say: "This method blocks until a datagram is received." By blocks it means never, ever returns. So the thread with the receive() is still running when you want your program to exit. It is a "hung thread" and the only way to relieve it is to kill the entire process, such as Ctrl+C.
您的 UDPReceive 线程没有停止的原因是您在 UDPReceive.run() while 循环中使用了阻塞方法DatagramSocket.receive()。此方法的 JavaDocs 说:“此方法阻塞,直到收到数据报。” 块意味着永远不会返回。因此,当您希望程序退出时,带有 receive() 的线程仍在运行。它是一个“挂起的线程”,唯一的缓解方法是杀死整个进程,例如Ctrl+C。
To fix it, call socket.setSoTimeout()before your UDPReceive.run() while loop starts. This will make the final call to receive() timeout and actually complete. Then catch the SocketTimeoutExceptionthat will occur if your socket times out (e.g. at the end of your program when the thread completes, or earlier if you have an actual timeout error condition) and handle the exception appropriately (e.g. if stopThread is triggered just ignore the exception, or if stopThread is not yet triggered log it as a warning). Example:
要修复它,请在循环开始时在UDPReceive.run()之前调用socket.setSoTimeout()。这将使对 receive() 的最终调用超时并实际完成。然后捕获SocketTimeoutException如果您的套接字超时(例如,在线程完成时程序结束时,或者如果您有实际超时错误条件,则更早)并适当处理异常(例如,如果 stopThread 被触发,只需忽略异常,或者如果 stopThread 尚未触发,则将其记录为警告)。例子:
public void run(){
DatagramSocket socket=null;
UDPpacket udp;
byte[] x = new byte[1000];
try{
socket = new DatagramSocket(8734);
socket.setBroadcast(true);
socket.setSoTimeout(20*1000); // 20 seconds
//while(this.p2p.getExit() !=-1){
while(stopThread){
p = new DatagramPacket(x,x.length);
try {
socket.receive(p);
} catch (SocketTimeoutException e) {
if (stopThread){
System.err.println("Warning: socket timed out " +
"before program completed: " + e.getLocalizedMessage());
} else {
// program completed, so just ignore and move on
break;
}
}
udp = new UDPpacket(p,this.p2p);
udp.tostring();
//udp.setDatagramPacket(p);
//String d = new String(p.getData());
//System.out.println("Mensagem enviada por mim: "+d);
}
//Thread.sleep(100);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This should do the trick. The stopThread logic itself looks fine (although I would rename the boolean to continueThread, because you're stopping when it is false).
这应该可以解决问题。stopThread 逻辑本身看起来不错(尽管我会将布尔值重命名为 continueThread,因为当它为false时您正在停止)。
回答by Damiii
Finally , i did it ! The result was a little different from what you guys said, I'll post my answer in case if anyone will ask it !
最后,我做到了!结果和你们说的有点不同,如果有人问的话,我会发布我的答案!
The solution was to send a DatagramPacket to myself ! :)
解决方案是向我自己发送一个 DatagramPacket !:)
Class udpReceiver ->
类 udpReceiver ->
//package testeThread;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
public class udpReceiver implements Runnable {
public volatile boolean stopThread = true;
private DatagramSocket socket;
//private DatagramSocket socket;
public udpReceiver() {
// TODO Auto-generated constructor stub
//this.socket = socket;
}
public void stopRun(){
synchronized(this){
this.stopThread=false;
byte[] x = new byte[1000];
try{
DatagramPacket p = new DatagramPacket(x,x.length,InetAddress.getLocalHost(),8737);
this.socket.send(p);
} catch(UnknownHostException e){
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
}
}
}
/**
* @param args
*/
public void run(){
//DatagramSocket socket=null;
DatagramPacket p = null;
//byte[] x = new byte[1000];
try{
this.socket = new DatagramSocket(8737);
this.socket.setBroadcast(true);
}catch(SocketException e){
e.printStackTrace();
}
//socket.setSoTimeout(5*1000); // 20 seconds
while(stopThread){
byte[] x = new byte[1000];
p = new DatagramPacket(x,x.length);
try{
this.socket.receive(p);
}catch(IOException e){
e.printStackTrace();
}
String d = new String(p.getData());
System.out.println("Mensagem enviada por mim: "+d);
}
this.socket.close();
/* try{
socket = new DatagramSocket(8735);
socket.setBroadcast(true);
//socket.setSoTimeout(5*1000); // 20 seconds
while(stopThread){
byte[] x = new byte[1000];
p = new DatagramPacket(x,x.length);
try {
socket.receive(p);
} catch (SocketTimeoutException e) {
if (stopThread){
//System.err.println("Warning: socket timed out before program completed: " + e.getLocalizedMessage());
} else {
// program completed, so just ignore and move on
break;
}
}
String d = new String(p.getData());
//System.out.println("Mensagem enviada por mim: "+d);
//System.out.println("SOCKET CLOSE"+socket.isConnected());
}
//socket.setSoTimeout(1000);
socket.close();
System.out.println("SOCKET CLOSE"+socket.isConnected());
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException io){
io.printStackTrace();
}*/
/*catch (SocketTimeoutException soc){
if(this.stopThread == false) {
this.stopThread = false;
}
soc.printStackTrace();
}*/
}
}
Class Servidor->
类服务器->
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.Scanner;
//package testeThread;
public class Servidor {
private int exit;
public Servidor() {
// TODO Auto-generated constructor stub
}
public int getExit(){
return this.exit;
}
public void setExit(int exit){
this.exit = exit;
}
public int choiceMenu(int i){
int numRowsInConsole = 60;
final String ESC = "3[";
switch(i){
case 1:
System.out.println("FUNCIONOU HELLO");
System.out.print(ESC + "2J");
/*for (int ii=0; ii<numRowsInConsole; ii++) {
// scroll down one line
System.out.println("");
}*/
break;
case 2:
System.out.println("FUNCIONOU VASCO");
System.out.print(ESC + "2J");
break;
case 3:
i=-1;
System.out.print(ESC + "2J");
break;
default:
}
return i;
}
public void menu(){
System.out.println("1:Hello");
System.out.println("2:");
System.out.println("3:Exit");
}
@SuppressWarnings("deprecation")
public static void main(String[] args) {
int i;
Servidor s = new Servidor();
//try{
//DatagramSocket socket = new DatagramSocket(8735);
udpReceiver udpR = new udpReceiver();
Thread t = new Thread(udpR);
t.start();
Scanner sc = new Scanner(System.in);
while(s.getExit() != -1){
s.menu();
i = sc.nextInt();
s.setExit(s.choiceMenu(i));
System.out.println(s.getExit());
}
//DatagramSocket socket = new DatagramSocket(8735);
//socket.close();
//t.interrupt();
udpR.stopRun();
try{
t.join();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("MAIN FIM");
//t.stop();
/*}catch(SocketException e){
e.printStackTrace();
}*/
}
}
P.S: that version isn't the same as the one upstairs ... But i get the same logic as i wrote the other one , and now it works good ! I can quit the program without using CTRL+C and it can receives the message now ! :)
PS:那个版本和楼上的不一样......但我得到的逻辑和我写的另一个一样,现在它运行良好!我可以在不使用 CTRL+C 的情况下退出程序,它现在可以接收消息!:)