I am trying to execute 2 jobs parallel from main thread but if a callback method take long time to give response rest of requests are pause and wait to complete first.
Here is my code:
private final ExecutorService executorService = Executors.newFixedThreadPool(10);
private void executeService(String uuid) {
System.out.println("query executed done: " + uuid);
}
private String getAsynchTest(final String uuid) throws Exception {
testAsynchF = executorService.submit(
new Callable<String>() {
public String call() throws Exception {
executeService(uuid);
return getFutuerResult(uuid, Thread.currentThread()); // long processing
}
});
return testAsynchF.get();
}
public String getFutuerResult(String uuid, Thread t) {
String dummy = "your result for request: "+uuid;
if (uuid.equalsIgnoreCase("112")) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return dummy;
}
public static void main(String[] args) {
SynchronousTimeoutTester tester = new SynchronousTimeoutTester();
try {
String one = "112"
System.out.println("Result sync call:*** " + tester.getAsynchTest(one));
String two = "115";
System.out.println("Result sync call:**** " + tester.getAsynchTest(two));
} catch (Exception e) {
System.out.println("catched as Exception: " + e);
}
}
Why is this stopping to execute request 115 if request 112 thread is pause?
Since you pass Thread.currentThread() to getFutureResult and that method calls join() on its thread argument (in case uuid is "112"), the method will wait for its own thread to end, which it can't since it's waiting.
Related
I have implemented a guava cache.In the load method of the guava cache I wanted to call a service asynchronously. I don't want to block this call for other thread, so, on it's call back I wanted to load the cache. How can I achieve this?
public CacheLoader(final DataValueProvider dataValueProvider) {
this.parentExecutor = Executors.newSingleThreadExecutor(new DefaultThreadFactory("cache-loader"));
this.executorService = MoreExecutors.listeningDecorator(parentExecutor);
this.secretValueProvider = secretValueProvider;
}
/**
* Call back method invoked by Guava to loads the initial value of the secretManager entry.
*/
#Override
public String load(CacheIndex cacheIndex) throws Exception {
return dataValueProvider.constructDataMangerFromSource(cacheIndex);
}
protected String constructDataMangerFromSource(CacheIndex cacheIndex) {
GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest()
.withSecretId(cacheIndex.secretArn);
Future<GetSecretValueResult> future = awsSecretsManagerAsync.getSecretValueAsync(
getSecretValueRequest, new AsyncHandler<GetSecretValueRequest, GetSecretValueResult>() {
#SneakyThrows
#Override
public void onError(Exception e) {
//I want to throw exception from here
}
#Override
public void onSuccess(GetSecretValueRequest request, GetSecretValueResult getSecretValueResult) {
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
logger.info("Total time taken in the call " + totalTime);
//I want to return the value from here
}
});
try {
//This is currently blocking other thread
GetSecretValueResult getSecretValueResult = future.get();
return getSecretValueResult.getSecretString();
} catch (Exception ex) {
logger.error("SecretManage call failed " + ex.getCause() + " " + ex.getMessage());
throw ex;
}
}
I am trying to write a simple function that long-polls multiple messages tothe downstream dependency without exhausting it and only exist when all messages succeeded.
I came up with a way to wrap each message polling into a callable and use a ExecutorService to submit a list of callables.
public void poll(final List<Long> messageIdList) {
ExecutorService executorService = Executors.newFixedThreadPool(messageIdList.size());
List<MessageStatusCallable> callables = messageIdList.stream()
.map(messageId -> new MessageStatusCallable(messageId)).collect(Collectors.toList());
boolean allSuccess = false;
try {
allSuccess = executorService.invokeAll(callables).stream().allMatch(success -> {
try {
return success.get().equals(Boolean.TRUE);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
} catch (ExecutionException e) {
e.printStackTrace();
return false;
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class MessageStatusCallable implements Callable<Boolean> {
private Long messageId;
public MessageStatusCallable(Long messageId) {
this.messageId = messageId;
}
/**
* Computes a result, or throws an exception if unable to do so.
*
* #return computed result
* #throws Exception if unable to compute a result
*/
#Override
public Boolean call() throws Exception {
String messageStatus = downstreamService.getMessageStatus(messageId);
while(messageStatus == null || !messageStatus.equals( STATUS_VALUE_SUCCEEDED) {
messageStatus = messageLogToControlServer.getMessageStatus(messageId);
Thread.sleep(TimeUnit.MICROSECONDS.toMillis(100));
}
LOG.info("Message: " + messageId + " Succeded");
return true;
}
}
I wonder if there is a better way to achieve this since Thread.sleep is blocking and ugly.
I'm not sure this is the best solution but it occurred to me you could use a CountDownLatch and ScheduledExecutorService.
public void poll(final List<Long> messageIdList) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(messageIdList.size());
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(POOL_SIZE);
try {
for (Long messageId : messageIdList) {
MessageStatusCallable callable = new MessageStatusCallable(messageId, latch);
executorService.scheduleWithFixedDelay(
() -> {
String messageStatus = downstreamService.getMessageStatus(messageId);
if (STATUS_VALUE_SUCCEEDED.equals(messageStatus)) {
latch.countDown();
throw new CompletionException("Success - killing the task", null);
}
},
0, 100, TimeUnit.MILLISECONDS);
}
latch.await();
} finally {
executorService.shutdown();
}
}
I probably also wouldn't have the Runnable as a lambda other than for brevity in the answer.
I am creating a system that will have multiple suite deployments and each deployment will have a queue of test suites. Since I want the test suites to run concurrently on their individual suite deployment, I need to add concurrency to the code. I have created a simplified version of the code I am using, but the concurrency portion doesn't work when I try to shut it down.
When the Runner.stopEverything() gets called, the result is that the queue gets emptied, and it waits for the threads to complete, but even when the tests all complete, the wait never finishes even with the notifyAll(). The result is that the process just sits there never ending. I go look at it in debug mode and the result is that all 3 threads show waiting.
Main:
public static void main(String args[]) throws Exception {
Runner.queueTestSuites("SD1", Arrays.asList("A", "B", "C"));
Runner.queueTestSuites("SD2", Arrays.asList("D", "E", "F"));
Runner.queueTestSuites("SD3", Arrays.asList("G", "H", "I"));
Thread.sleep(5000);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~");
Runner.stopEverything();
}
Runner:
public class Runner {
private static Map<String, TestQueue> runnerQueueMap = new ConcurrentHashMap<>();
public synchronized static void queueTestSuites(String suiteDeployment, List<String> testSuiteQueueAsJSON) throws Exception {
TestQueue queue;
if(runnerQueueMap.containsKey(suiteDeployment)) {
queue = runnerQueueMap.get(suiteDeployment);
} else {
queue = new TestQueue(suiteDeployment);
}
for (int i = 0; i < testSuiteQueueAsJSON.size(); i++) {
String name = testSuiteQueueAsJSON.get(i);
queue.addToQueue(name);
}
runnerQueueMap.put(suiteDeployment,queue);
}
public synchronized static void stopEverything() throws InterruptedException {
for (String s : runnerQueueMap.keySet()) {
TestQueue q = runnerQueueMap.get(s);
q.saveAndClearQueue();
}
for (String s : runnerQueueMap.keySet()) {
TestQueue q = runnerQueueMap.get(s);
q.waitForThread();
}
System.out.println("All done at " + new Date());
}
}
TestQueue:
public class TestQueue {
private Consumer consumer;
private Thread consumerThread;
private java.util.concurrent.BlockingQueue<String> queue;
private String suiteDeployment;
public TestQueue(String suiteDeployment) {
this.suiteDeployment = suiteDeployment;
queue = new ArrayBlockingQueue<>(100);
startConsumer();
}
public void addToQueue(String testSuite) {
try {
queue.put(testSuite);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void waitForThread() {
try {
if (consumer.running.get()) {
synchronized (consumerThread) {
System.out.println("Waiting for " + consumerThread.getName());
consumerThread.wait();
}
}
System.out.println("Thread complete at " + new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void saveAndClearQueue() {
List<String> suiteNames = new ArrayList<>();
for (String suite : queue) {
suiteNames.add(suite);
}
queue.clear();
}
private void startConsumer() {
consumer = new Consumer(queue,suiteDeployment);
consumerThread = new Thread(consumer);
consumerThread.start();
}
private class Consumer implements Runnable{
private BlockingQueue<String> queue;
private String suiteDeployment;
public AtomicBoolean running;
public Consumer(BlockingQueue<String> queue, String suiteDeployment){
this.queue = queue;
this.suiteDeployment = suiteDeployment;
this.running = new AtomicBoolean(false);
}
#Override
public void run() {
try{
while(!Thread.currentThread().isInterrupted()) {
String testSuite = queue.take();
this.running.set(true);
new Test(testSuite, suiteDeployment).run();
this.running.set(false);
}
notifyAll();
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
Test:
public class Test {
String testSuite = "";
String suiteDeployment = "";
public Test(String testSuite, String suiteDeployment) {
this.testSuite = testSuite;
this.suiteDeployment = suiteDeployment;
}
public void run() {
int time = new Random().nextInt() % 10000;
time = Math.max(time, 3000);
System.out.println("Test Started: " + testSuite + " on " + suiteDeployment + " at " + new Date() + " running for " + time + " on thread " + Thread.currentThread().getName());
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Test Completed: " + testSuite + " on " + suiteDeployment + " at " + new Date());
}
}
Inside run method of your consumer, you have a blocking call to queue.take() which means it will block until there is an item inside your queue. You run out of elements inside the queue eventually and all your thread are blocked by the queue.take() call waiting for more elements to become available to process.
Although your call is in a while loop where it check if the thread is interrupted, you actually never interrupt the threads so it never gets to the while loop evaluation & blocked at the call to queue.take()
So your threads stay in wait as they are waiting for input to become avilable inside your blocking queue
Also your saveAndClear method must lock on the correct object which is the queue itself, like below:
public void saveAndClearQueue() {
List<String> suiteNames = new ArrayList<String>();
synchronized (queue) {
for (String suite : queue) {
suiteNames.add(suite);
}
queue.clear();
}
System.out.println("Saved(not executed) : "+suiteNames);
}
And your waitForThread method should do sth like below:
public void waitForThread() {
synchronized (consumerThread) {
while (consumer.running.get()) {
try {
consumerThread.wait(100);
} catch (InterruptedException e) {
break;
}
}
}
if (!consumer.running.get()) {
consumerThread.interrupt();
}
System.out.println("Thread complete at " + new Date());
}
This is my Class. I am using a Quartz scheduler and in that once a job is toBeExecuted, I wanted to avoid concurrency..hence used Synchronize keyword.. and used wait for each thread but it seems that once job is executed..Notify doesnt call the waiting thread ..please help...stuck on this from last two days:
public class SJobListener implements JobListener {
public static final String LISTENER_NAME = "SchedulerJobListener";
ExecutingClass compSched = new ExecutingClass();
#Override
public String getName() {
return LISTENER_NAME; //must return a name
}
// Run this if job is about to be executed.
#Override
public void jobToBeExecuted(JobExecutionContext context) {
String jobName = context.getJobDetail().getKey().toString();
System.out.println("jobToBeExecuted");
System.out.println("Listener : Job : " + jobName + " is going to start...");
System.out.println("Thread running in jobToBeExecuted :"+Thread.currentThread().getName()+" "+Thread.currentThread().getId());
synchronized (compSched) {
if(!condition)
try {
System.out.println("Going to Wait");
Thread.currentThread().wait(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//Run this after job has been executed
#Override
public void jobWasExecuted(JobExecutionContext context,
JobExecutionException jobException) {
System.out.println("jobWasExecuted");
String jobName = context.getJobDetail().getKey().toString();
System.out.println("Listener :Job : " + jobName + " is finished...");
System.out.println("Thread running in jobWasExecuted :"+Thread.currentThread().getName()+" "+Thread.currentThread().getId());
//synchronized (compSched) {
System.out.println("Notifying waiting threads");
//context.notifyAll();
Thread.currentThread().notifyAll();
if (!jobException.getMessage().equals("")) {
System.out.println("Exception thrown by: " + jobName
+ " Exception: " + jobException.getMessage());
jobException.printStackTrace();
}
System.out.println("Out Of jobWasExecuted");
}
}
Thanks in advance.
Please read on java concurrency:
Threads wait on a lock. This lock is what is used to notify other threads waiting on the same lock.
Consider:
public class SynchronizedExample{
private final Object LOCK = new Object();
public void doSomethingOr() {
if(somethingIsNotDone()) {
synchronize(LOCK) {
LOCK.wait(); //trycatch here
}
}
}
public void somethingSone() {
somethingIsDone = true;
synchronized(LOCK) {
LOCK.notifyAll(); //trycatch
}
}
}
Replace Thread.currentThread().wait(200); with compSched.wait(200).
And in jobWasExecuted you should call notify on compSched
The methods jobToBeExecuted and jobWasExecuted are running in different threads so you are waiting on a different object and expecting notifications on a different object. That is why it does not work.
If you explained your requirements a bit more succinctly, a different solution could be provided other than wait notify mechanism.
I refer to this link to create a fixed size threadpool. Then I have a method which allow submit Callable request and get the result, it look like this:
private ExecutorService threadPool = Executors.newFixedThreadPool(5);
private CompletionService<String> pool = new ExecutorCompletionService<String>(threadPool);
public void execute(Callable<String> request){
pool.submit(request);
// what happen if this method is called before get the result???
try {
String result = pool.take().get();
System.out.println("result is " + result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
This execute method can be called many times and the request has difference execute time. The problem is that I want to get the result immediately when it finished. And I want to make sure when executing this method, other calls can be handled and allow add to thread poll.
Here is an example usage:
final Random rnd = new Random();
for (int i = 0; i < 5; i++) {
final String value = String.valueOf(i);
execute(new Callable<String>() {
#Override
public String call() throws Exception {
int sleep = rnd.nextInt(10) * 100;
System.out.println("sleep in " + sleep);
Thread.sleep(sleep);
return value;
}
});
}
And the results are always in order although they have difference execute time:
sleep in 900
result is 0
sleep in 300
result is 1
sleep in 0
result is 2
sleep in 500
result is 3
sleep in 600
result is 4
And I also used the future, but it doesn't work too.
private static void execute(Callable<String> request){
Future<String> future = threadPool.submit(request);
try {
String result = future.get();
System.out.println("result is " + result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
Please tell me how can I do that? Thanks in advance.
You aren't using the CompletionService correctly. Your main thread is producing tasks and consuming results. A CompletionService is intended to decouple production and consumption; you'd use it when you have different threads playing these roles. The execute() method makes no sense; it is effectively doing this, but with a lot of obfuscation and overhead:
public void execute(Callable<String> request) {
try {
System.out.println("result is " + request.call());
} catch (Exception ex) {
ex.printStackTrace();
}
}
If you must consume the result as soon as it's ready, you have to make that part of the task. Otherwise, you need one application thread waiting for every task to complete, because if you don't, a task result might be ready and have to wait for a thread to be available to consume it. And if you have one thread per task already, why use a thread pool?
To be more explicit, if you want to guarantee no waiting, you need to do something like this:
final class MyTask implements Callable<Void> {
private final String value;
MyTask(String value) { this.value = value; }
#Override
public Void call() throws InterruptedException {
String result = doWork();
handleResult(result);
return null;
}
private String doWork() throws InterruptedException {
int sleep = ThreadLocalRandom.current().nextInt(10) * 100;
System.out.println("sleep in " + sleep);
Thread.sleep(sleep);
return value;
}
private void handleResult(String result) {
System.out.println("result is " + result);
}
}
If you want to use a CompletionService, you need some separate threads that take() from the service. But in this approach, if tasks are completed faster than they are consumed, some results will wait.
R4j,
the get() waits for the callable to return with the value from call: if you want to submit 5 requests you need to submit all requests and then call get