I'm trying to run an async bash command from a java file and wait for it to finish before I continue the java code execution.
At this moment I've tried using Callable like so:
class AsyncBashCmds implements Callable{
#Override
public String call() throws Exception {
try {
String[] cmd = { "grep", "-ir", "<" , "."};
Runtime.getRuntime().exec(cmd);
return "true"; // need to hold this before the execution is completed.
} catch (Exception e) {
return "false";
}
}
}
and I call it like so:
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future<String> future = executorService.submit(new runCPPinShell(hookResponse));
String isFinishedRunningScript = future.get();
Thanks!!!
An easier way is to use Java 9+ .onExit():
private static CompletableFuture<String> runCmd(String... args) {
try {
return Runtime.getRuntime().exec(args)
.onExit().thenApply(pr -> "true");
} catch (IOException e) {
return CompletableFuture.completedFuture("false");
}
}
Future<String> future = runCmd("grep", "-ir", "<" , ".");
String isFinishedRunningScript = future.get(); // Note - THIS will block.
If you want to block anyway, use .waitFor().
Related
very basic code to run asynchronous method.
when I run the following code the runAsync doesn't run.
what I'm missing?
the result run only the sync code .
public class Main {
public static void main(String[] args) {
runAsync("run async command ans wait 10000");
System.out.println("sync commands ");
}
public static void runAsync(String inputStr) {
CompletableFuture.runAsync(() -> {
List<String> strings = Arrays.asList(inputStr.split(" "));
int sleep = Integer.parseInt(strings.get(strings.size() - 1));
try {
sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("async command ");
});
}
}
I expect to get first the "sync commands" then the "async command "
but get only the sync message
Your task will run in some other Thread(by default in a Thread from ForkJoinPool) and you are not waiting for it to finish - the main Thread ends before your async task is executed/submitted. You can call CompletableFuture::join to wait for it to finish and it will block the main Thread until it finishes :
CompletableFuture.runAsync(() -> {
List<String> strings = Arrays.asList(inputStr.split(" "));
int sleep = Integer.parseInt(strings.get(strings.size() - 1));
try {
sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("async command ");
}).join(); //here call the join
or like :
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
//...
});
cf.join();
You need to wait for the async task to be completed by using join, for example:
public static void main(String[] args) {
CompletableFuture<Void> future = runAsync("run async command ans wait 10000");
future.join();
System.out.println("sync commands ");
}
public static CompletableFuture<Void> runAsync(String inputStr) {
return CompletableFuture.runAsync(() -> {
List<String> strings = Arrays.asList(inputStr.split(" "));
int sleep = Integer.parseInt(strings.get(strings.size() - 1));
try {
sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("async command ");
});
}
It does run, but it runs on another thread and you're not waiting or doing anything with the result. As Javadoc of CompletableFuture.runAsync() says:
Returns a new CompletableFuture that is asynchronously completed by a
task running in the ForkJoinPool.commonPool() after it runs the given
action.
runAsync() is useful for tasks that don't return anything. If you want a result from it you should use supplyAsync() which returns a CompletableFuture<T>
Then you can get the result from it:
// Run a task specified by a Supplier object asynchronously
CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
#Override
public String get() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of the asynchronous computation";
}
});
// Block and get the result of the Future
String result = future.get();
System.out.println(result);
I am trying to call a method multiple times every 60 seconds until a success response from the method which actually calls a rest end point on a different service. As of now I am using do while loop and using
Thread.sleep(60000);
to make the main thread wait 60 seconds which I feel is not the ideal way due to concurrency issues.
I came across the CountDownLatch method using
CountDownLatch latch = new CountDownLatch(1);
boolean processingCompleteWithin60Second = latch.await(60, TimeUnit.SECONDS);
#Override
public void run(){
String processStat = null;
try {
status = getStat(processStatId);
if("SUCCEEDED".equals(processStat))
{
latch.countDown();
}
} catch (Exception e) {
e.printStackTrace();
}
}
I have the run method in a different class which implements runnable. Not able to get this working. Any idea what is wrong?
You could use a CompletableFuture instead of CountDownLatch to return the result:
CompletableFuture<String> future = new CompletableFuture<>();
invokeYourLogicInAnotherThread(future);
String result = future.get(); // this blocks
And in another thread (possibly in a loop):
#Override
public void run() {
String processStat = null;
try {
status = getStat(processStatId);
if("SUCCEEDED".equals(processStat))
{
future.complete(processStat);
}
} catch (Exception e) {
future.completeExceptionally(e);
}
}
future.get() will block until something is submitted via complete() method and return the submitted value, or it will throw the exception supplied via completeExceptionally() wrapped in an ExecutionException.
There is also get() version with timeout limit:
String result = future.get(60, TimeUnit.SECONDS);
Finally got it to work using Executor Framework.
final int[] value = new int[1];
pollExecutor.scheduleWithFixedDelay(new Runnable() {
Map<String, String> statMap = null;
#Override
public void run() {
try {
statMap = coldService.doPoll(id);
} catch (Exception e) {
}
if (statMap != null) {
for (Map.Entry<String, String> entry : statMap
.entrySet()) {
if ("failed".equals(entry.getValue())) {
value[0] = 2;
pollExecutor.shutdown();
}
}
}
}
}, 0, 5, TimeUnit.MINUTES);
try {
pollExecutor.awaitTermination(40, TimeUnit.MINUTES);
} catch (InterruptedException e) {
}
I have been working with threads to send a GET request to a link (all good). However, I need it to run asynchronously, so I made a new thread and ran it. Problem is I need it to return the value returnVar[0] after the thread is done executing. I have tried while loops with !thread.isActive but of course, the method body needs a return statement. I have tried CountdownLatches which you are about to see, but they pause the main thread which I DON'T want. Any ideas are greatly appreciated.
Code:
public String getUUID(String username) {
final String[] returnVar = {"ERROR"};
final CountDownLatch latch = new CountDownLatch(1);
Thread thread = new Thread(() -> {
final String[] response = {"ERROR"};
final JSONObject[] obj = new JSONObject[1];
response[0] = ConnectionsManager.sendGet("https://api.mojang.com/users/profiles/minecraft/" + username);
try {
obj[0] = (JSONObject) new JSONParser().parse(response[0]);
returnVar[0] = (String) obj[0].get("id");
} catch (ParseException e) {
e.printStackTrace();
}
latch.countDown();
});
thread.start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return returnVar[0];
}
I think you should consider using a Callable instead of a Runnable. See this thread for explanation and examples.
Also, it's a little strange that you are using the CountDownLatch with one thread. The latch is useful to make sure multiple threads are started as uniformly as possible rather than some threads getting a 'head start' in a more traditional startup.
this is an improper use of Threads.
your code runs exactly like the below code :
public String getUUID(String username) {
String response = ConnectionsManager.sendGet("https://api.mojang.com/users/profiles/minecraft/" + username);
try {
return (String) ((JSONObject) new JSONParser().parse(response)).get("id");
} catch (ParseException e) {
return "ERROR";
}
}
there are several options to make async call.
one option is to use CompletableFuture :
CompletableFuture.supplyAsync(getUUID("username")).thenAccept(new Consumer<String>() {
#Override
public void accept(String response) {
// response of async HTTP GET
}
});
learn more :
http://www.javaworld.com/article/2078809/java-concurrency/java-concurrency-java-101-the-next-generation-java-concurrency-without-the-pain-part-1.html
http://javarevisited.blogspot.nl/2015/01/how-to-use-future-and-futuretask-in-Java.html
Difference between Future and Promise
https://www.javacodegeeks.com/2011/09/java-concurrency-tutorial-callable.html
http://winterbe.com/posts/2015/04/07/java8-concurrency-tutorial-thread-executor-examples/
http://www.infoq.com/articles/Functional-Style-Callbacks-Using-CompletableFuture
I call the below testMethod, after putting it into a Callable(with other few Callable tasks), from an ExecutorService. I suspect that, the map.put() suffers OutOfMemoryError, as I'm trying to put some 20 million entries.
But, I'm not able to see the error trace in console. Just the thread stops still. I tried to catch the Error ( I know.. we shouldnt, but for debug I caught). But, the error is not caught. Directly enters finally and stops executing.. and the thread stands still.
private HashMap<String, Integer> testMethod(
String file ) {
try {
in = new FileInputStream(new File(file));
br = new BufferedReader(new InputStreamReader(in), 102400);
for (String line; (line= br.readLine()) != null;) {
map.put(line.substring(1,17),
Integer.parseInt(line.substring(18,20)));
}
System.out.println("Loop End"); // Not executed
} catch(Error e){
e.printStackTrace(); //Not executed
}finally {
System.out.println(map.size()); //Executed
br.close();
in.close();
}
return map;
}
Wt could be the mistake, I'm doing?
EDIT: This is how I execute the Thread.
Callable<Void> callable1 = new Callable<Void>() {
#Override
public Void call() throws Exception {
testMethod(inputFile);
return null;
}
};
Callable<Void> callable2 = new Callable<Void>() {
#Override
public Void call() throws Exception {
testMethod1();
return null;
}
};
List<Callable<Void>> taskList = new ArrayList<Callable<Void>>();
taskList.add(callable1);
taskList.add(callable2);
// create a pool executor with 3 threads
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<Void>> future = executor.invokeAll(taskList);
//executor.invokeAll(taskList);
latch.await();
future.get(0);future.get(1); //Added this as per SubOptimal'sComment
But, this future.get() didn't show OOME in console.
You should not throw away the future after submitting the Callable.
Future future = pool.submit(callable);
future.get(); // this would show you the OOME
example based on the informations of the requestor to demonstrate
public static void main(String[] args) throws InterruptedException, ExecutionException {
Callable<Void> callableOOME = new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println("callableOOME");
HashMap<String, Integer> map = new HashMap<>();
// some code to force an OOME
try {
for (int i = 0; i < 10_000_000; i++) {
map.put(Integer.toString(i), i);
}
} catch (Error e) {
e.printStackTrace();
} finally {
System.out.println("callableOOME: map size " + map.size());
}
return null;
}
};
Callable<Void> callableNormal = new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println("callableNormal");
// some code to have a short "processing time"
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException ex) {
System.err.println(ex.getMessage());
}
return null;
}
};
List<Callable<Void>> taskList = new ArrayList<>();
taskList.add(callableOOME);
taskList.add(callableNormal);
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<Void>> future = executor.invokeAll(taskList);
System.out.println("get future 0: ");
future.get(0).get();
System.out.println("get future 1: ");
future.get(1).get();
}
Try catching Throwable as it could be an Exception like IOException or NullPointerException, Throwable captures everything except System.exit();
Another possibility is that the thread doesn't die, instead it becomes increasingly slower and slower due to almost running out of memory but never giving up. You should be able to see this with a stack dump or using jvisualvm while it is running.
BTW Unless all you strings are exactly 16 characters long, you might like to call trim() on the to remove any padding in the String. This could make them shorter and use less memory.
I assume you are using a recent version of Java 7 or 8. If you are using Java 6 or older, it will use more memory as .substring() doesn't create a new underlying char[] to save CPU, but in this case wastes memory.
I hava a test, with:
#test(timeout = 50000)
I want to do some operations if the test fails because the timeout, and only then.
I try the next:
#Test(timeout=60000)
public void test1() {
try{
// code
}
catch(Exception e){
//operations after time out
}
}
But it doesn't work. Any help?
It's not possible to do what you described here with JUnit's timeout parameter because it doesn't provide a callback to handle the operations after it has timed out.
But, you can certainly write your own test harness to do just that. In the below example, I want the code to execute within one second but my actual code execution takes 2 seconds. In this case, we catch the TimeoutException and you can perform your additional operation within that catch block.
#Test
public void testMe() {
// test must finish within one second
int expectedExecutionInSeconds = 1;
RunnableFuture<String> runnableFuture = new FutureTask<String>(new Callable<String>() {
public String call() throws Exception {
// your actual code goes in here
Thread.sleep(2000);
return "ok";
}
});
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(runnableFuture);
try {
String result = runnableFuture.get(expectedExecutionInSeconds, TimeUnit.SECONDS);
assertEquals("ok", result);
}
catch (TimeoutException ex) {
// stop code
runnableFuture.cancel(true);
System.out.println("do other stuff");
}
catch (Exception e) {
fail("other stuff is failing");
}
executorService.shutdown();
}