2011-05-30 27 views
0

我有一個關於Java線程化的問題。在我的代碼,線程獲得控制權,然後殺死它

... 
client.doSth(); 
// now need to get hold of the thread that is initiated by 'client' 
(get a reference to the 'client' thread) 
// now kills it 
(kills the 'client' thread) 
... 

所以我想知道的是:在第一個括號,我怎麼編程方式獲得一個參考的抱到「客戶」線程(不是主線程程序上運行),並在第二個括號中,我如何正確地殺死它,即不使用depreciated stop()方法。

非常感謝。

+0

'doSth()'方法是否返回一個Thread對象? – 2011-05-30 11:53:53

+0

你爲什麼不''客戶端'返回一個'Thread'?沒有這些,你如何期望能夠確定正確的線程? – 2011-05-30 11:54:03

+0

@Oli Charlesworth:事情是客戶端對象是由我使用的第三方庫創建的,所以我不能修改它的行爲,並且在這種情況下,爲了讓它返回由'客戶端'對象啓動的線程。 – skyork 2011-05-30 12:25:41

回答

1

編輯: 重讀的問題後,我不知道任何更多,如果你有機會到客戶端的代碼。如果你這樣做,那麼你可以修改它,甚至不使用線程,但java.util.concurrent.ExecutorService或類似的..但

由於代碼不是你自己的...你是在你自己停止它。

ThreadGroup類是專爲。管理部分程序或模塊並不容易,通常需要一些已經建立的框架。確保一些第三方代碼的行爲良好,並不總是可能的。它應該包括上下文類加載器和什麼不是,但這裏是它的完成過程的簡化版本。

儘管如此,你仍然可以做些什麼來打破入侵者的骨骼。假設已經使用了stop()/ close()等,在日誌記錄等一些技巧像ThreadDeath。

ThreadGroup g=new ThreadGroup("client X group"); 

Runnable r=new Runnable(){ 
public void run(){ 
    client.doSmth();//assuming a new thread is started... 
} 
} 
Thread t= new Thread(g, r, "clientStarter"); 
t.start(); 

//stopping, last resort code, it's usually more complicated than just thread.stop, though 

//now you can enumerate threads of the ThreadGroup 
synchronized(g){//sync ensures no more threads will be created, use it w/ extreme caution 
    Thread[] threads = new Thread[g.activeCount()]; 
    for(Thread thread:threads){ 
    if(thread==null) break; 
    thread.stop();// 
    //cannot join in sync of ThreadGroup, do not use it here 
    } 
    } 

祝你好運!

0

如果doSth()方法返回一個Thread對象,則可以執行以下操作;

Thread t = client.doSth(); 
t.interrupt(); 
+0

謝謝。但是我如何做一個方法(在這種情況下,dosth())返回由'client'對象啓動的線程? – skyork 2011-05-30 12:22:05

1

你可以創建你的客戶一個stpSth()方法調用來阻止它

public class Client(){ 
    private Thread t; 
    volatile private boolean stop;//volatile to ensure visibility across threads 
    public doSth(){ 
     stop=false; 
     Runnable r = new Runnable(){ 
      @Override 
      public void run(){ 
       while(!stop){ 
        //do stuff and periodically and ensure that interrupts bubble through 
       } 
      } 
     }; 

     t = new Thread(r); 
     t.start(); 
    } 

    public void stopSht(){ 
     stop=true; 
     t.interupt(); 
    } 
} 
+0

感謝您的輸入,但有兩件事:第一個客戶端類不在我使用的第三方庫中,所以我不能真正修改它。其次,是不是應該這樣!停止運行方法內的while循環?謝謝。 – skyork 2011-05-30 12:30:19

+0

@skyork確實它應該是'!stop'我的壞,如果你不能得到線程(即沒有你的代碼是由它執行,它從來沒有給它的參考),你在爲一個雖然一。除非庫有一個方法來殺死客戶的線程... – 2011-05-30 12:42:41

2

要顯示的主題樹做這樣的:

,你可以這樣做:

// Find the root thread group 
ThreadGroup root = Thread.currentThread().getThreadGroup().getParent(); 
while (root.getParent() != null) { 
    root = root.getParent(); 
} 

// Visit each thread group 
visit(root, 0); 

// This method recursively visits all thread groups under `group'. 
public static void visit(ThreadGroup group, int level) { 
    // Get threads in `group' 
    int numThreads = group.activeCount(); 
    Thread[] threads = new Thread[numThreads*2]; 
    numThreads = group.enumerate(threads, false); 

    System.out.println(" "); 

    // Enumerate each thread in `group' 
    for (int i=0; i<numThreads; i++) { 
     // Get thread 
     Thread thread = threads[i]; 
     System.out.println(thread.toString()); 
    } 

    // Get thread subgroups of `group' 
    int numGroups = group.activeGroupCount(); 
    ThreadGroup[] groups = new ThreadGroup[numGroups*2]; 
    numGroups = group.enumerate(groups, false); 

    // Recursively visit each subgroup 
    for (int i=0; i<numGroups; i++) { 
     visit(groups[i], level+1); 
     } 

} 

您可以選擇調用,顯示堆棧跟蹤一個特定線程ID的方法:

System.out.println(thread.dumpStack()); 

現在你有ID殺:

int idToKill = 2; 
int active = Thread.activeCount(); 
System.out.println("currently active threads: " + active); 
Thread all[] = new Thread[active]; 
Thread.enumerate(all); 
for (int i = 0; i < active; i++) { 
    System.out.println(i + ": " + all[i]); 
    if(idToKill == i) 
    ((Thread) all[i]).interrupt(); 
} 
+0

我在類似的思路。你知道idToKill是如何分配的嗎? – Atreys 2011-05-30 12:49:17

+0

代碼被破壞,你不能比較一個索引和一個id,並期望得到完美的結果 – bestsss 2011-05-30 13:02:30

+0

是的,同意Atreys的意見,我將如何最初分配idToKill來匹配我打算殺死的正確線程?謝謝。 – skyork 2011-05-30 13:07:17

1

我在comment中看到您正在使用kryonet API。

kryonet爲Client對象提供了一個stop()方法。如果你使用start()創建一個線程來啓動客戶端,並且stop()應該停止它。

以下是啓動和停止kryonet服務器和客戶端的代碼片段,顯示進程中各個點的活動線程。 2秒睡眠是讓線程在要求停止時結束。

import java.io.IOException; 
import java.util.Arrays; 

import com.esotericsoftware.kryonet.Client; 
import com.esotericsoftware.kryonet.Server; 

public class KryonetAndThreads { 
    public static void main(String[] args) throws IOException, 
      InterruptedException { 
     Server s = new Server(); 
     s.start(); 
     s.bind(1927); 
     printThreads("server started"); 

     Client c = new Client(); 
     c.start(); 
     c.connect(5000, "LOCALHOST", 1927); 
     printThreads("client connected"); 
     Server s1 = s; 
     s.stop(); 
     printThreads("server stopped"); 

     s = new Server(); 
     s.start(); 
     s.bind(1928); 
     printThreads("new server started"); // new server thread will be last on 
              // the list. 

     c.stop(); 
     printThreads("client stopped"); 

     c.start(); 
     c.connect(5000, "localhost", 1928); 
     printThreads("client connected to second server"); 

     c.stop(); 
     s.stop(); 
     s1.stop(); 
     printThreads("both stopped"); 
    } 

    private static void printThreads(String message) 
      throws InterruptedException { 
     // tick: 
     Thread.sleep(2000L); 
     Thread[] threads = new Thread[Thread.activeCount()]; 
     Thread.enumerate(threads); 
     System.out.println(message + " : " + Arrays.asList(threads)); 
    } 
} 
+0

感謝您的建議。是的,這是我從API中得到的印象,但是,如果您先執行client.stop(),然後立即執行client.start(),然後執行client.connect(...)到新服務器,它將不會讓您。一些異常會拋出,說現有的客戶端線程無法建立新的連接,這似乎表明client.stop()並沒有真正殺死舊的線程。 – skyork 2011-05-31 02:46:32