简体   繁体   中英

Threadpool executor not updating the concurrent hashmap

I am spawning 5 threads using the thread pool executor to execute 5 different commands in parallel. After completion of each thread i am updating the concurrent hashmap with the entries of threadid as a key and terminated as value. But my threadpool is not updating the hashmap of the successful completion of the commands execution.

Main Class:

package com.cisco.executor;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class MainExecutor {

    static String element;
    static ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<Integer, String>();
    static Integer array[] = { 1, 2, 3, 4, 5 };
//  static Integer array[] = { 1 };
    static List<Integer> threadid = Arrays.asList(array);
    static String SQOOP_XXCCS_DS_SAHDR_CORE = ReadProperties.getInstance().getProperty("SQOOP_XXCCS_DS_SAHDR_CORE");
    static String SQOOP_XXCCS_DS_CVDPRDLINE_DETAIL = ReadProperties.getInstance()
            .getProperty("SQOOP_XXCCS_DS_CVDPRDLINE_DETAIL");
    static String SQOOP_XXCCS_DS_INSTANCE_DETAIL = ReadProperties.getInstance()
            .getProperty("SQOOP_XXCCS_DS_INSTANCE_DETAIL");
    static String SQOOP_XXCCS_SCDC_PRODUCT_PROFILE = ReadProperties.getInstance()
            .getProperty("SQOOP_XXCCS_SCDC_PRODUCT_PROFILE");
    static String SQOOP_MTL_SYSTEM_ITEMS_B = ReadProperties.getInstance().getProperty("SQOOP_MTL_SYSTEM_ITEMS_B");

    public static void main(String[] args) {

        ThreadPoolExecutor executors = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
//      ThreadPoolExecutor executors = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);

        System.out.println("at executors step");
        List<String> getlist = getList();
        Iterator<Integer> itr2 = threadid.iterator();

        for (Iterator<String> itr = getlist.iterator(); itr.hasNext() && itr2.hasNext();) {
            String element = (String) itr.next();
            int thread_id = itr2.next();
            String[] command = { "ssh", "hddev-c01-edge-02", "\"" + element + "\"" };
            System.out.println("the command is as below ");
            System.out.println(Arrays.toString(command));
            System.out.println("inside the iterator");
            ParallelExecutor pe = new ParallelExecutor(command, thread_id, map);
            executors.execute(pe);
        }
        // executors.shutdown();
        for(Map.Entry<Integer, String> entry: map.entrySet())
        {
            Integer key = entry.getKey();
            String value = entry.getValue();            
            System.out.println("The key is " + key + " The value is " + value);
            System.out.println("Thread " + key + " is terminated");
        }

    }

    public static List<String> getList() {
        List<String> commandlist = new ArrayList<String>();
        System.out.println("inside getList");
        commandlist.add(SQOOP_XXCCS_DS_SAHDR_CORE);
        commandlist.add(SQOOP_XXCCS_DS_CVDPRDLINE_DETAIL);
        commandlist.add(SQOOP_XXCCS_DS_INSTANCE_DETAIL);
        commandlist.add(SQOOP_XXCCS_SCDC_PRODUCT_PROFILE);
        commandlist.add(SQOOP_MTL_SYSTEM_ITEMS_B);
        return commandlist;
    }

}

Runnable Class:

package com.cisco.executor;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Logger;

public class ParallelExecutor implements Runnable {

    private static Logger LOGGER = Logger.getLogger(ParallelExecutor.class);

    String[] command;
    int threadid;
    ConcurrentHashMap<Integer, String> map;

    public ParallelExecutor(String[] command, int threadid, ConcurrentHashMap<Integer, String> map) {
        this.command = command;
        this.threadid = threadid;
        this.map = map;
    }

    @Override
    public void run() {
        ProcessBuilder processbuilder = new ProcessBuilder(command);
        LOGGER.info(command);
        try {
            Process process = processbuilder.inheritIO().start();
            System.out.println("inside process builder ");
            process.waitFor();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String readline;
            while ((readline = reader.readLine()) != null) {
                LOGGER.info(readline);
            }
            // getting the thread state and adding it to a collection
            Thread.State state = Thread.currentThread().getState();
            if (state == Thread.State.TERMINATED) {
                map.put(threadid, "TERMINATED");
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
        }
    }

}

Is my implementation wrong. Can someone help me with the implementation.

Instead of trying to capture the outcome of a thread in the thread (which is error prone esp if an exception/error is thrown) I suggest you retain the Future objects and inspect those.

    ExecutorService exec = Executors.newFixedThreadPool(5);

    System.out.println("at executors step");
    Map<String, Future<?>> results = new HashMap<>();
    for (String element : getList()) {
        String[] command = { "ssh", "hddev-c01-edge-02", "\"" + element + "\"" };
        results.put(element, exec.submit(new ParallelExecutor(command, thread_id, map)));
    }
    for(Map.Entry<String, Future<?>> entry: map.entrySet()) {
        try {
            entry.getValue().get();
            System.out.println(entry.getKey()+ " is complete");
        } catch (ExecutionException e) {
            System.out.println(entry.getKey()+ " failed with");
            e.getCause().printStackTrace(System.out);
        }
    }

ThreadPoolExecutor does not terminate untill it is asked to do so. So, first of all you have to call

// executors.shutdown();

, which you kept as commented. 2nd, you need to wait for the threads to terminate properly. for that add a loop, before for(Map.Entry entry: map.entrySet())

while (!es.isTerminated()) {
        }

But, since one thread will probably run many runnables and if I get you correctly you want to update the CHM once one Runnable is done with it's execution.

To do that, you have to use a CustomThread class. extends Thread and override just 1 method, afterExecute() where from you need to put code to update CHM with Runnable 's id and terminated status. But remember this means completion of passed Runnables run() method, not the underlying Thread's termination.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM