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