0

I have a question regarding threading in Java. In my code,

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

So what I would like to know is: in the first brackets, how do I programmatically get hold of a reference to the 'client' thread (NOT the main thread the program is running on), and in the second brackets, how do I properly kill it, i.e. without using the depreciated stop() method.

Many thanks.

skyork
  • 7,113
  • 18
  • 63
  • 103
  • Does the 'doSth()' method return a Thread object? – Iñigo Beitia May 30 '11 at 11:53
  • Why don't you just have `client` return a `Thread`? Without that, how do you expect to be able to identify the correct thread? – Oliver Charlesworth May 30 '11 at 11:54
  • @Oli Charlesworth: the thing is that the client object is created out of a third-party library which I use, so I cannot modify its behavior, and in this case, to get it return the thread initiated by 'client' object. – skyork May 30 '11 at 12:25
  • @skyork: Then I think you may be out of options... – Oliver Charlesworth May 30 '11 at 12:57
  • @Oli, killing 3rd party lib's threads is a walk in a park once mastered... – bestsss May 30 '11 at 14:37
  • @Skyork, right you have quite a few options and interrupt() is hardly a one (unfortunately). you can use `Thread.currentThread().getId()` and enumerate it later to use `Thread.stop()`, stop method is a difficult one to use properly and I do not recommend it, though. There is more to the case, I will try to elaborate in an answer – bestsss May 30 '11 at 14:39

5 Answers5

2

To show the Thread tree do like that :

you can do like this :

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

}

You can choose to call a method that shows the stackTrace for a specified Thread id :

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

Now you have the id to kill :

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();
}
EricParis16
  • 809
  • 5
  • 9
  • I was thinking along similar lines. Do you have an idea of how idToKill would be assigned? – Atreys May 30 '11 at 12:49
  • the code is broken, you cant compare an index to an id and expect a flawless result – bestsss May 30 '11 at 13:02
  • yes, agree with Atreys' comments, how would I initially assign idToKill to match the correct thread i intend to kill? thanks. – skyork May 30 '11 at 13:07
  • This can potentially work IF the library being used actually assigns a name to the thread. Then you can compare the Thread.getName() to see if you have a match. You can check for a name assignment in a debugger. – Robin May 30 '11 at 13:41
  • of course this code is an example not the solution. I was thinking you had an swing interface or HTML which could show the list of threads, and the dumpStack() method could help you to decide which thread is to be killed. – EricParis16 May 30 '11 at 14:21
1

you can create a stpSth() method in your Client and call that to stop it

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();
    }
}
ratchet freak
  • 47,288
  • 5
  • 68
  • 106
  • appreciate your input, but two things: first Client class is out of a third-party library which I use, so I cannot really modify it. second, isn't it supposed to be !stop for that while loop inside the run method? thanks. – skyork May 30 '11 at 12:30
  • @skyork indeed it should be `!stop` my bad on that, if you can't get the thread (i.e. none of your code is executed by it and it never gives a reference to it) you're in for a though one. unless the library has a method somewhere to kill Client's threads... – ratchet freak May 30 '11 at 12:42
1

Edit: after rereading the question I am not sure any more if you have access to the client code. If you do, well you can revise it and not even use thread but java.util.concurrent.ExecutorService or the likes.. yet

Since the code is not your own... you are on your own to stop it.

ThreadGroup class is designed for. Managing partial programs or modules is not exactly easy and usually it takes some already established framework. Ensuring some 3rd party code will behave and be nice and all it's not always possible. It should include context classloader and what not but here is a skimmed version of how it's done.

Still there might be something you can do to break the bone of the intruder. Assuming stop()/close(), etc has been used, some tricks like ThreadDeath during logging and so on.

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

Good luck!

bestsss
  • 11,796
  • 3
  • 53
  • 63
1

I see in the comment you are using kryonet API.

kryonet supplies a stop() method for Client objects. If you start the client using start() creates a Thread, and stop() should stop it.

Following is a snippet to start and stop kryonet servers and clients, showing the active threads at various points in the process. The 2 second sleep is to let the threads come to an end when they are requested to stop.

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));
    }
}
Community
  • 1
  • 1
Atreys
  • 3,741
  • 1
  • 17
  • 27
  • thanks for the suggestions. Yes, that's the impression I get from the API, however, if you do client.stop() immediately followed by client.start(), and then client.connect(...) to a new server, it won't let you. Some exception will throw, saying that a new connection cannot be made on the existing Client thread, which seems to suggest that client.stop() doesn't really kill the old thread. – skyork May 31 '11 at 02:46
0

If the doSth() method returns a Thread object, you can do the following;

Thread t = client.doSth();
t.interrupt();
Iñigo Beitia
  • 6,303
  • 4
  • 40
  • 46
  • thanks. but how exactly do I make a method (in this case, dosth()) to return the thread that is initiated by object 'client'? – skyork May 30 '11 at 12:22