Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dispose Child Thread As per the Id

I am generating a child thread when I receive data from user.

What are the steps if I want to dispose the previous user child thread if the same user sends data again and wants to generate a new user child thread again?

like image 603
Suraj Khanra Avatar asked Jan 17 '17 12:01

Suraj Khanra


2 Answers

Right, so java can't dispose of the thread, a thread simply runs until it terminates. So: To get rid of the thread you need to allow the threads run method to end and then get rid of all references to the Thread and any Runnable it's constructed with.

You want to toggle the thread finishing so, a simple example:

class SimpleRunnable implements Runnable {
public volatile boolean run = true;  //Volatile for thread safety.

public void run() {
        while(run) {
                System.out.println("WHOOOO!"); //Boy, will this be annoying     
        }
    }
}

Creating a thread from this runnable:

SimpleRunnable run = new SimpleRunnable();
Thread thread = new Thread(run);  
Thread.start(); //run thread
//Stop thread 
run.run=false;
//Thread will be removed when out of scope

Youu need to create a Runnable per user in your case, and then call set the stop variable when a new thread is created. For example, you could store each runnable in a ConcurrentHashMap by userId.

ConcurrentHashMap<String,SimpleRunnable> runnablesByUser = new ConcurrentHashMap<>();

public void startNewThreadForUser(String userId){
//Time passes, retrieve and kill old thread:
SimpleRunnable oldRunnable = runnableByUser.get(userId);
if(oldRunnable!=null){
   oldRunnable.run=false;
}
SimpleRunnable newRunnableUserOne = new SimpleRunnable();
runnablesByUser.put(userId,newRunnableUserOne);
Thread thread = new Thread(newRunnableUserOne);
thread.start();
}

Calls to the method would then kill an old thread if found, release the old one from scope by replacing it with a new one in the ConcurrentHashMap and finally start the new thread. Like so:

public void startThreeThreads(){
    startNewThreadForUser("User1");//starts Thread for User1
    startNewThreadForUser("User2");//starts Thread for User2
    startNewThreadForUser("User1");//Replaces Thread for User1
}

Managing running threads is typically done in a thread pool and this is rough in all sorts of ways, but hopefully it's useful.

I can elaborate that mechanism if you want.

like image 142
chargedPeptide Avatar answered Nov 05 '22 07:11

chargedPeptide


In case you want the ability to cancel a task that has already been submitted to the thread pool, you will have to keep reference of the Future values of each task, and make sure to remove the reference of the tasks that completed and that you cancelled, so they are ready to be garbage collected (otherwise you will have a memory leak).

for example

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class MultipleClientsExample {

    public static final int TOTAL_THREADS_TO_PROCESS_CUSTOMER_WORK = 4;

    public static int customerCounter = 0;


    public static void main(String[] args) throws InterruptedException {
        MultipleClientsExample multipleClientsExample = new MultipleClientsExample();
        multipleClientsExample.doTheWork();
    }

    private void doTheWork() throws InterruptedException {

        final ExecutorService executorService = Executors.newFixedThreadPool(TOTAL_THREADS_TO_PROCESS_CUSTOMER_WORK);

        Map<String, Future<String>> map = new ConcurrentHashMap<>();

        while (customerCounter < 11) {

            try {
                WorkToBeDone workToBeDone = getWorkFromCustomer();
                System.out.println("main program. received work from customer: " + workToBeDone.getClientId());

                Future<String> resultFuture = executorService.submit(workToBeDone);
                map.put(workToBeDone.getClientId(), resultFuture);

            } catch (InterruptedException e) {
                break;
            }
            customerCounter++;

        }


        // cancel job of customer with id: 10

        Future<String> resultFuture = map.get("10");
        System.out.println("cancelling job of customerId: 10");
        resultFuture.cancel(true);


        // remove references of all completed jobs

        Thread.sleep(2000);

        System.out.println("looking for jobs that completed or were cancelled.");
        Iterator<Map.Entry<String, Future<String>>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Future<String>> entry = iterator.next();
            if (entry.getValue().isCancelled() || entry.getValue().isDone()) {
                System.out.println("removing reference of job for customer: " + entry.getKey());
                iterator.remove();
            }
        }

        // simpler way to remove entries from map (but doesn't print output of jobs removed from map)
        // map.entrySet().removeIf(entry -> entry.getValue().isCancelled() || entry.getValue().isDone());


        executorService.shutdown();
        executorService.awaitTermination(5, TimeUnit.SECONDS);

    }

    private WorkToBeDone getWorkFromCustomer() throws InterruptedException {
        String customerId = String.valueOf(customerCounter);
        WorkToBeDone workToBeDone = new WorkToBeDone(customerId, "work from customer: " + customerId);
        return workToBeDone;
    }
}


class WorkToBeDone implements Callable<String> {

    private String clientId;
    private String workInfo;


    public String getClientId() {
        return clientId;
    }

    public WorkToBeDone(String clientId, String workInfo) {
        this.clientId = clientId;
        this.workInfo = workInfo;
    }


    @Override
    public String call() throws Exception {
        System.out.println("inside a working thread: it is going to do the work of customer: " + clientId);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println("worker processing job from customer: " + clientId + " was interrupted. ending now");
            return clientId;
        }

        System.out.println("work completed for customer: " + clientId);
        return clientId;
    }
}
like image 41
Jose Zevallos Avatar answered Nov 05 '22 07:11

Jose Zevallos