Note that there are some explanatory texts on larger screens.

plurals
  1. POUsing Spring threading and TaskExecutor, how do I know when a thread is finished?
    primarykey
    data
    text
    <p>Alright, possible a naive question here. I have a service that needs to log into multiple network devices, run a command on each and collect the results. For speed, rather than collect the information on each device in sequence, I need to access them all concurrently and consume the results after they are done. </p> <p>Using the Spring framework and Jsch I'm quite easily able to query each device correctly. Where I am running into some confusion is in trying to rewire the beans to use TaskExecutor to accomplish this. What I can't figure out how to do is how to know when the thread is finished.</p> <p>What I have so far is this:</p> <pre><code>public class RemoteCommand { private String user; private String host; private String password; private String command; private List&lt;String&gt; commandResults; private TaskExecutor taskExecutor; public RemoteCommand(String user, String host, String password, TaskExecutor taskExecutor) { setUser(user); setHost(host); setPassword(password); setTaskExecutor(taskExecutor); } /** * @param user the user to set */ public void setUser(String user) { this.user = user; } /** * @return the user */ public String getUser() { return user; } /** * @param host the host to set */ public void setHost(String host) { this.host = host; } /** * @return the host */ public String getHost() { return host; } /** * @param password the password to set */ public void setPassword(String password) { this.password = password; } /** * @return the password */ public String getPassword() { return password; } /** * @param command the command to set */ private void setCommand(String command) { this.command = command; } /** * @return the command */ private String getCommand() { return command; } /** * @param commandResults the commandResults to set */ private void setCommandResults(List&lt;String&gt; commandResults) { this.commandResults = commandResults; } /** * @return the commandResults */ public List&lt;String&gt; getCommandResults(String command) { taskExecutor.execute(new CommandTask(command) ); return commandResults; } /** * @param taskExecutor the taskExecutor to set */ public void setTaskExecutor(TaskExecutor taskExecutor) { this.taskExecutor = taskExecutor; } /** * @return the taskExecutor */ public TaskExecutor getTaskExecutor() { return taskExecutor; } private class CommandTask implements Runnable { public CommandTask(String command) { setCommand(command); System.out.println("test: " + getCommand()); } /** * * @param command */ public void run() { List&lt;String&gt; results = new LinkedList&lt;String&gt;(); String command = getCommand(); try { System.out.println("running"); JSch jsch = new JSch(); String user = getUser(); String host = getHost(); java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); host = host.substring(host.indexOf('@') + 1); Session session = jsch.getSession(user, host, 22); session.setPassword(getPassword()); session.setConfig(config); session.connect(); Channel channel = session.openChannel("exec"); ((ChannelExec) channel).setCommand(command); channel.setInputStream(null); ((ChannelExec) channel).setErrStream(System.err); InputStream in = channel.getInputStream(); channel.connect(); byte[] tmp = new byte[1024]; while (true) { while (in.available() &gt; 0) { int i = in.read(tmp, 0, 1024); if (i &lt; 0) break; results.add(new String(tmp, 0, i)); System.out.print(new String(tmp, 0, i)); } if (channel.isClosed()) { //System.out.println("exit-status: " // + channel.getExitStatus()); break; } try { Thread.sleep(1000); } catch (Exception ee) { ee.printStackTrace(); } } channel.disconnect(); session.disconnect(); } catch (Exception e) { System.out.println(e); } setCommandResults(results); System.out.println("finished running"); } } } </code></pre> <p>Within my junit test I have:</p> <pre><code>@Test public void testRemoteExecution() { remoteCommand = (RemoteCommand) applicationContext.getBean("remoteCommand"); remoteCommand.getCommandResults("scripts/something.pl xxx.xxx.xxx.xxx"); //List&lt;String&gt; results = remoteCommand.getCommandResults("scripts/something.pl xxx.xxx.xxx.xxx"); //for (String line : results) { // System.out.println(line.trim()); //} } </code></pre> <p>My applicationContext.xml file:</p> <pre><code> &lt;bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"&gt; &lt;property name="corePoolSize" value="5" /&gt; &lt;property name="maxPoolSize" value="10" /&gt; &lt;property name="queueCapacity" value="25" /&gt; &lt;/bean&gt; &lt;!-- ******************** --&gt; &lt;!-- Utilities --&gt; &lt;!-- ******************** --&gt; &lt;bean name="remoteCommand" class="com.xxx.ncc.sonet.utilities.RemoteCommand" scope="prototype"&gt; &lt;description&gt;Remote Command&lt;/description&gt; &lt;constructor-arg&gt;&lt;value&gt;${remote.user}&lt;/value&gt;&lt;/constructor-arg&gt; &lt;constructor-arg&gt;&lt;value&gt;${remote.host}&lt;/value&gt;&lt;/constructor-arg&gt; &lt;constructor-arg&gt;&lt;value&gt;${remote.password}&lt;/value&gt;&lt;/constructor-arg&gt; &lt;constructor-arg ref="taskExecutor" /&gt; &lt;/bean&gt; </code></pre> <p>I get as far as the first println in the run() method. Then the test exits cleanly with no errors. I never get to the second println at the bottom of that routine. I've looked at this thread <a href="https://stackoverflow.com/questions/702415/how-to-know-if-other-threads-have-finished">here</a>, which was very useful, but not implemented in a Spring specific fashion. I'm sure I'm missing something simple, or have completely run off the rails here. Any help is appreciated.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload