-3

私は 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();


}

}

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();
    }

}

}

p2p_app クラスのメイン関数でスレッドを強制終了するにはどうすればよいですか? UDPreceiver クラスのスレッドを作成します:F

4

4 に答える 4

3

ほとんどの場合、スレッドを強制終了する唯一の「安全な」方法は、停止するシグナルを受信できるようにスレッドをコーディングすることです。たとえば、呼び出されたブール変数を使用しshouldQuit、スレッドにその変数を定期的にチェックさせ、それが true の場合は終了します。スレッドを中断するなどのこともできますが、常に安全とは限りません。

于 2013-04-24T21:47:25.337 に答える
0

UDPReceive スレッドが停止しない理由は、UDPReceive.run() while ループでブロッキング メソッドDatagramSocket.receive()を使用しているためです。このメソッドの JavaDoc には、「このメソッドはデータグラムが受信されるまでブロックされます」と書かれています。ブロックとは、決して戻ってこないことを意味します。したがって、プログラムを終了させたいときは、 receive() を含むスレッドがまだ実行されています。これは「ハング スレッド」であり、それを緩和する唯一の方法は、Ctrl+C などでプロセス全体を強制終了することです。

これを修正するには、UDPReceive.run () while loop の開始前に 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 のときに停止しているためです)。

于 2013-04-25T13:26:54.890 に答える