-3

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).

Class 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->

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

Damiii
  • 9
  • 1
  • 1
  • 3
  • 2
    Code the thread only to do work you want it to do and to terminate itself when there's no work for it to do. Then you won't need to "reach in from the outside" to stop it. – David Schwartz Apr 24 '13 at 21:49
  • Well, Java is a slow changing language so, new answers will be most likely the old answers. What have you tried and in what way it did not work? – madth3 Apr 24 '13 at 22:02
  • i tried the : public volatile boolean stopThread = true; public void stopRun(){ this.stopThread=false; } as i tried also the interupted function for Thread.. And both didnt work it yet – Damiii Apr 24 '13 at 22:05
  • well i saw that article before i wrote my question and it didnt resolved it... – Damiii Apr 24 '13 at 22:38
  • Then you're not applying the concepts correctly, but the concepts in that link *are* correct and as you're seeing are essentially the same as the answers that you're receiving here. – Hovercraft Full Of Eels Apr 24 '13 at 23:45
  • "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." So ? i did the same thing as it was said on your article ! The problem isn't there ... it's something else ... – Damiii Apr 25 '13 at 15:45
  • @HovercraftFullOfEels as you can see the answer wasn't that properly ! ;) I wasn't putting the concept incorrectly ! ;) – Damiii Apr 26 '13 at 15:23

4 Answers4

3

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.

KyleM
  • 4,445
  • 9
  • 46
  • 78
  • Well on my example above , i tried that method and it doesnt seems to work :f At least when i try to quit the application on my command line , it doesn't quit .. i must do CTRL+C to quit it .. – Damiii Apr 24 '13 at 21:51
  • @user2317427 You said this is a java program. You'd have to set shouldQuit=true from another Java thread. Can you edit your original post and more fully explain how you expect to quit the thread? – KyleM Apr 24 '13 at 21:54
  • @user2317427 Also ctrl+c is implemented on most operating systems to send an interrupt. So when you type ctrl+c the currently executing program/thread will be interrupted, transferring control back to the operating system, which will then kill your program. That process isn't java specific...\ – KyleM Apr 24 '13 at 21:55
  • Well,the expectation is that : There is a Main function on my class p2p_app and what i want to do on my main function is : run a thread for my class UDPreceiver, do the while statement, if the while statement is ended => kill all my threads and quit the program . – Damiii Apr 24 '13 at 21:58
  • @user2317427 Also, if you want to wait for Threads to finish executing, you can use the Thread.join method (you can call Thread.join on each Thread in an array of Threads from your main method, for example). – KyleM Apr 25 '13 at 03:42
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();
    }
}
} 

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..

Barranka
  • 20,547
  • 13
  • 65
  • 83
0

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.

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 SocketTimeoutException that 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:

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).

Will
  • 6,601
  • 3
  • 31
  • 42
  • how am i able to make that part "if stopThread is triggered just ignore the exception, or if stopThread is not yet triggered log it as a warning)." ? Ignoring the exception ? If the Socket.setSoTimeout() is done, my thread is already out and i cannot go back... at least from what i tried, i got that ... – Damiii Apr 25 '13 at 14:16
  • Ok, see my updated answer with code sample. And please accept if it works for you. ;) In general it is good practice to be aware of using blocking vs. non-blocking I/O, and plan for possible timeouts. Also, handle exceptions appropriately for your use case; mine is just an example. – Will Apr 25 '13 at 16:13
  • ok,that worked now, i can quit the program without using CTRL+C ! But i cant receive my datagrampacket now ... lol When i was able to receive them before lol – Damiii Apr 25 '13 at 16:32
  • As you discovered in your answer, my solution will only work for receiving packets until there are no more to receive. In your original code you weren't sending any packets. I assumed you'd be adding that later... which you did. ;) – Will Apr 25 '13 at 18:44
  • well that one i wasnt sending, but on my other pc i wrote some code to send me some packets ! :) – Damiii Apr 25 '13 at 21:16
0

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 ! :)

Class 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 = "\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: 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 ! :)

Damiii
  • 9
  • 1
  • 1
  • 3
  • Heh, yeah you won't receive any packets if none are sent. – Will Apr 25 '13 at 18:46
  • actually , i have two pc's one who sends packets and mine who receives ! With that code, i would able to receive code from my other pc and also quit the program without using the CTRL+C ! :) – Damiii Apr 25 '13 at 21:18