如何杀死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上的线程? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

杀死音频剪辑线程

Java中的杀死或销毁或退出线程[重复]

服务器进程的查看和杀死

java在超时值后杀死线程[重复]

如何防止主线程ios杀死后台线程

如何从工作线程中调用 UI 线程上的方法? [复制]