如何杀死java上的线程? [复制]
Posted
技术标签:
【中文标题】如何杀死java上的线程? [复制]【英文标题】:How to kill a thread on java? [duplicate] 【发布时间】:2013-04-18 15:20:02 【问题描述】:我对用 java 杀死一个线程感到头疼...... 我在***上看到了很多主题,但我没有让他们处理我的代码...... 有人可以解释一下我如何能够在不使用不推荐使用的函数(如停止)的情况下以安全的方式杀死一个线程(我的线程也在运行一个套接字:DatagramSocket)。
类 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 = "\033[";
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();
类 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();
如何在 p2p_app 类中杀死我的主函数上的线程?我为我的 UDPreceiver 类创建了一个线程:F
【问题讨论】:
对线程进行编码,只为完成您希望它完成的工作,并在没有工作可做时自行终止。那么你就不需要“从外面伸手进去”来阻止它了。 嗯,Java 是一种变化缓慢的语言,因此,新答案很可能是旧答案。您尝试了哪些方法,但以何种方式不起作用? 我试过了:public volatile boolean stopThread = true; public void stopRun() this.stopThread=false; 因为我也尝试了 Thread 的中断功能.. 两者都没有工作 好吧,我在写我的问题之前就看到了那篇文章,但它没有解决它...... 那么您没有正确应用这些概念,但是该链接中的概念是正确的,并且您所看到的与您的答案基本相同在这里接收。 【参考方案1】:在大多数情况下,杀死线程的唯一“安全”方法是对线程进行编码,使其能够接收到停止信号。例如,使用名为shouldQuit
的布尔变量并让线程定期检查该变量,如果为真则退出。你也可以做一些事情,比如中断线程,但这并不总是安全的。
【讨论】:
好吧,在我上面的例子中,我尝试了那个方法,但它似乎不起作用:f 至少当我尝试在命令行上退出应用程序时,它不会退出......我必须这样做CTRL+C 退出它.. @user2317427 你说这是一个java程序。您必须从另一个 Java 线程设置 shouldQuit=true 。您能否编辑您的原始帖子并更全面地解释您希望如何退出该主题? @user2317427 在大多数操作系统上也实现了 ctrl+c 来发送中断。因此,当您键入 ctrl+c 时,当前正在执行的程序/线程将被中断,将控制权转移回操作系统,然后操作系统将终止您的程序。该过程不是特定于 java 的...\ 嗯,期望是:我的类 p2p_app 上有一个 Main 函数,我想在我的 main 函数上做的是:为我的类 UDPreceiver 运行一个线程,执行 while 语句,如果while 语句结束 => 杀死我所有的线程并退出程序。 @user2317427 另外,如果你想等待线程完成执行,你可以使用 Thread.join 方法(你可以从你的 main 方法调用线程数组中的每个线程 Thread.join ,例如)。【参考方案2】: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();
如果你打算停止你创建的线程,出于任何原因,你应该继续跟踪它们并持有对你可能想要停止的每个线程的引用,而不是等待它自己完成执行(运行方法简单结束)。 在这个简单的测试中,如果您删除停止循环,线程将继续打印并且永远不会停止,直到您手动停止它们,即使在主线程终止之后也是如此。 我希望这很有用..
【讨论】:
为什么在 run() 上使用 sleep(1000)? sleep(1000) :告诉当前线程休眠(等待)1000 毫秒 是的,但有必要吗? 它有时很有用。在这种情况下,我用它来模拟“做某事”。在现实世界中,线程会忙于等待客户端连接/消息/输入,或者执行一些大代码块..【参考方案3】:您的 UDPReceive 线程没有停止的原因是您在 UDPReceive.run() while 循环中使用了阻塞方法 DatagramSocket.receive()。此方法的 JavaDocs 说:“此方法阻塞,直到收到数据报。”块意味着永远不会返回。因此,当您希望程序退出时,带有 receive() 的线程仍在运行。它是一个“挂起的线程”,唯一的解除方法就是杀死整个进程,比如Ctrl+C。
要修复它,请在 UDPReceive.run() while 循环开始之前调用 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();
这应该可以解决问题。 stopThread 逻辑本身看起来不错(尽管我会将布尔值重命名为 continueThread,因为当它为 false 时你会停止)。
【讨论】:
我如何才能使该部分“如果触发了 stopThread,则忽略异常,或者如果尚未触发 stopThread,则将其记录为警告)。” ?忽略异常?如果 Socket.setSoTimeout() 完成了,我的线程已经出来了,我不能回去了……至少从我尝试过的来看,我明白了…… 好的,请查看我的更新答案和代码示例。如果它适合你,请接受。 ;) 一般来说,了解使用阻塞与非阻塞 I/O 并计划可能的超时是一种很好的做法。此外,为您的用例适当处理异常;我的只是一个例子。 好的,现在可以了,我可以在不使用 CTRL+C 的情况下退出程序!但是我现在无法收到我的数据报包……哈哈,当我能够在之前收到它们时,哈哈 正如您在回答中发现的那样,我的解决方案仅适用于接收数据包,直到不再接收数据包为止。在您的原始代码中,您没有发送任何数据包。我以为您稍后会添加它……您确实这样做了。 ;) 嗯,我没有发送,但在我的另一台电脑上,我写了一些代码来发送一些数据包! :)【参考方案4】:终于,我做到了! 结果和你们说的有点不一样 如果有人问,我会发布我的答案!
解决方案是给自己发送一个 DatagramPacket ! :)
类 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();
*/
类服务器->
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 = "\033[";
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:那个版本和楼上那个不一样……但是我得到了和我写另一个一样的逻辑,现在它工作得很好!我可以在不使用 CTRL+C 的情况下退出程序,它现在可以接收消息了! :)
【讨论】:
嘿,是的,如果没有发送任何数据包,您将不会收到任何数据包。 实际上,我有两台电脑,一台发送数据包,我的一台接收!使用该代码,我将能够从我的另一台电脑接收代码并退出程序而无需使用 CTRL+C ! :)以上是关于如何杀死java上的线程? [复制]的主要内容,如果未能解决你的问题,请参考以下文章