如何在java上杀死一个线程?

时间:2013-04-24 21:43:32

标签: java multithreading sockets kill

我在用java杀死一个线程时很头疼... 我在stackoverflow上看到了很多主题,我没有让他们处理我的代码...... 有人可以解释我如何能够在不使用弃用函数(如停止)的情况下杀死线程并以安全的方式取悦(我的线程正在运行套接字: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();


}

}

Classe UDPreceive-&gt;

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

4 个答案:

答案 0 :(得分:3)

在大多数情况下,唯一的&#34;安全&#34;杀死线程的方法是以一种可以接收停止信号的方式对线程进行编码。例如,使用一个名为shouldQuit的布尔变量,让Thread定期检查该变量,如果它是真的则退出。你也可以做一些像打断线程的东西,但这并不总是安全的。

答案 1 :(得分: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方法)简单地结束)。 在这个简单的测试中,如果你移除了停止循环,线程将继续打印并且永远不会停止,直到手动停止它们,即使在主线程终止之后。 我希望这很有用..

答案 2 :(得分:0)

您的UDPReceive线程未停止的原因是您在循环中使用UDPReceive.run()中的阻塞方法DatagramSocket.receive()。此方法的JavaDocs说:“此方法将一直阻塞,直到收到数据报。”通过块,它意味着永远不会返回。因此,当您希望程序退出时,带有receive()的线程仍在运行。它是一个“挂起的线程”,解除它的唯一方法是终止整个过程,例如Ctrl + C.

要修复它,请在循环启动时在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();
    }

}

这应该可以解决问题。 stopThread逻辑本身看起来很好(虽然我会将boolean重命名为continueThread,因为当它 false 时你就停止了。)

答案 3 :(得分:0)

最后,我做到了! 结果与你们所说的有点不同, 如果有人问的话,我会发布我的答案!

解决方案是向我自己发送一个DatagramPacket! :)

班级udpReceiver - &gt;

//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-&gt;

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的情况下退出程序,它现在可以收到消息! :)