I am trying to change Quartz Sequential execution to Parallel Execution.
It is working fine, Performance wise, it is seems good but Spawned (created) threads are not destroyed.
It is Still in Runnable State; why and How can I fix that?
Please Guide me.
Code is here :
#Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.error("Result Processing executed");
List<Object[]> lstOfExams = examService.getExamEntriesForProcessingResults();
String timeZone = messageService.getMessage("org.default_timezone", null, Locale.getDefault());
if(lstOfExams!=null&&!lstOfExams.isEmpty()){
ThreadPoolTaskExecutor threadPoolExecuter = new ThreadPoolTaskExecutor();
threadPoolExecuter.setCorePoolSize(lstOfExams.size());
threadPoolExecuter.setMaxPoolSize(lstOfExams.size()+1);
threadPoolExecuter.setBeanName("ThreadPoolTaskExecutor");
threadPoolExecuter.setQueueCapacity(100);
threadPoolExecuter.setThreadNamePrefix("ThreadForUpdateExamResult");
threadPoolExecuter.initialize();
for(Object[] obj : lstOfExams){
if(StringUtils.isNotBlank((String)obj[2]) ){
timeZone = obj[2].toString();
}
try {
Userexams userexams=examService.findUserExamById(Long.valueOf(obj[0].toString()));
if(userexams.getExamresult()==null){
UpdateUserExamDataThread task=new UpdateUserExamDataThread(obj,timeZone);
threadPoolExecuter.submit(task);
}
// testEvaluator.generateTestResultAsPerEvaluator(Long.valueOf(obj[0].toString()), obj[4].toString(), obj[3]==null?null:obj[3].toString(),timeZone ,obj[5].toString() ,obj[1].toString());
// logger.error("Percentage Marks:::::"+result.getPercentageCatScore());
} catch (Exception e) {
Log.error("Exception at ResultProcessingJob extends QuartzJobBean executeInternal(JobExecutionContext context) throws JobExecutionException",e);
continue;
}
}
threadPoolExecuter.shutdown();
}
}
UpdateUserExamDataThread .class
#Component
//#Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
//public class UpdateUserExamDataThread extends ThreadLocal<String> //implements Runnable {
public class UpdateUserExamDataThread implements Runnable {
private Logger log = Logger.getLogger(UpdateUserExamDataThread.class);
#Autowired
ExamService examService;
#Autowired
TestEvaluator testEvaluator;
private Object[] obj;
private String timeZone;
public UpdateUserExamDataThread(Object[] obj,String timeZone) {
super();
this.obj = obj;
this.timeZone = timeZone;
}
#Override
public void run() {
String threadName=String.valueOf(obj[0]);
log.info("UpdateUserExamDataThread Start For:::::"+threadName);
testEvaluator.generateTestResultAsPerEvaluator(Long.valueOf(obj[0].toString()), obj[4].toString(), obj[3]==null?null:obj[3].toString(),timeZone ,obj[5].toString() ,obj[1].toString());
//update examResult
log.info("UpdateUserExamDataThread End For:::::"+threadName);
}
}
TestEvaluatorImpl.java
#Override
#Transactional
public Examresult generateTestResultAsPerEvaluator(Long userExamId, String evaluatorType, String codingLanguage,String timeZoneFollowed ,String inctenceId ,String userId) {
dbSchema = messageService.getMessage("database.default_schema", null, Locale.getDefault());
try {
//Some Methods
return examResult;
}catch(Exception e){
log.erorr(e);
}
}
I can provide Thread Dump file if needed.
it seems you create a thread pool in the same size of exams which is not quite optimal.
// Core pool size is = number of exams
threadPoolExecuter.setCorePoolSize(lstOfExams.size());
// Max pool size is just 1 + exam size.
threadPoolExecuter.setMaxPoolSize(lstOfExams.size()+1);
You have to consider that:
- If you create a thread pool and started it as many threads as defined in core size started immediately.
The max pool size is only than effective when you submit more than core pool threads can process right now AND when the queue size is full (in this case 100). So that means a new thread will be only then created when the number of submitted tasks exceeded 100+exam size.
In your case I would set the core pool size 5 or 10 (it actually depends on the how many core your target CPU have and/or how IO bound the submitted tasks are).
The max pool size can be double of that but it doesn't effective until the queue is full.
To let the size of live threads decrease after the submitted work done you have to set 2 parameters.
setKeepAliveSeconds(int keepAliveSeconds) : Which let the threads shut down automatically if they are not used along the defined seconds (by default 60 seconds, which is optimal) BUT this is normally only used to shut down threads of non-core pool threads.
To shut down threads of core part after keepAliveSeconds you have to set setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) as true. Which is normally false to keep core pool alive as long as the application is running.
I hope it helps.
I suspect that one of your threads waits indefinitely for an IO request answer. For example, you try to connect to a remote host where you did not set connection timeout and the host does not answer. In this case, you can shutdown all executing tasks forcefully by running shutdownNow method of the underlying ExecutorService then you can analyze InterruptedIOException thrown by the offending threads.
Replace
threadPoolExecuter.shutdown();
with below so you can examine errors.
ExecutorService executorService = threadPoolExecuter.getThreadPoolExecutor();
executorService.shutdownNow();
This will send interrupt signal to all running threads.
The threads do not wait on IO from some remote server, because the executed method on the threads would be in some jdbc driver classes, but they are currently all in UpdateUserExamDataThread.run(), line 37.
Now the question is: what is the code at UpdateUserExamDataThread.java line 37 ?
Unfortunately, the UpdateUserExamDataThread.java given at the moment is incomplete and/or not the version really executed: the package declaration is missing and it ends at line 29.
I suspect the issue is simply that you are calling run() instead of execute() when spawning the task thread using submit(). There is probably some expectation when using submit that threads kill themselves when the task is finished rather than terminating at the end of the run method.
Just Needed to increase the priority of threads and create number of threads as per number of cores in processor.
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.error("Result Processing executed");
List<Object[]> lstOfExams = examService.getExamEntriesForProcessingResults();
String timeZone = messageService.getMessage("org.default_timezone", null, Locale.getDefault());
int cores = Runtime.getRuntime().availableProcessors();
if(lstOfExams!=null&&!lstOfExams.isEmpty()){
ThreadPoolTaskExecutor threadPoolExecuter = new ThreadPoolTaskExecutor();
threadPoolExecuter.setCorePoolSize(cores);
// threadPoolExecuter.setMaxPoolSize(Integer.MAX_VALUE);
threadPoolExecuter.setBeanName("ThreadPoolTaskExecutor");
// threadPoolExecuter.setQueueCapacity(Integer.MAX_VALUE);
threadPoolExecuter.setQueueCapacity(lstOfExams.size()+10);
threadPoolExecuter.setThreadNamePrefix("ThreadForUpdateExamResult");
threadPoolExecuter.setWaitForTasksToCompleteOnShutdown(true);
threadPoolExecuter.setThreadPriority(10);
threadPoolExecuter.initialize();
for(Object[] obj : lstOfExams){
if(StringUtils.isNotBlank((String)obj[2]) ){
timeZone = obj[2].toString();
}
try {
Userexams userexam=examService.findUserExamById(Long.valueOf(obj[0].toString()));
if(userexam.getExamresult()==null){
UpdateUserExamDataThread task=new UpdateUserExamDataThread(obj,timeZone,testEvaluator);
// threadPoolExecuter.submit(task);
threadPoolExecuter.execute(task);
}
// testEvaluator.generateTestResultAsPerEvaluator(Long.valueOf(obj[0].toString()), obj[4].toString(), obj[3]==null?null:obj[3].toString(),timeZone ,obj[5].toString() ,obj[1].toString());
// logger.error("Percentage Marks:::::"+result.getPercentageCatScore());
} catch (Exception e) {
logger.error("Exception at ResultProcessingJob extends QuartzJobBean executeInternal(JobExecutionContext context) throws JobExecutionException",e);
continue;
}
}
threadPoolExecuter.shutdown();
}
}
Related
I'm creating a Threadpool as shown below for a job.
public class MoveToCherwellThreadPool {
public static ThreadPoolExecutor cherwellMoveThreadPoolExecutor = null;
private static EMLogger logger = EMLogger.getLogger();
private static final String CLASSNAME = "MoveToCherwellThreadPool";
public static void initiateCherwellMoveThreadPool() {
BlockingQueue<Runnable> q = new LinkedBlockingQueue<Runnable>(100000);
cherwellMoveThreadPoolExecutor = new ThreadPoolExecutor(10,20, 20, TimeUnit.SECONDS, q);
cherwellMoveThreadPoolExecutor.setRejectedExecutionHandler(new RejectedExecutionHandler() {
#Override
public void rejectedExecution(Runnable r,
ThreadPoolExecutor executor) {
logger.logDebug(CLASSNAME,"Rejected task cherwellMoveThreadPoolExecutor Active tasks : " + cherwellMoveThreadPoolExecutor.getActiveCount() + ", " + "cherwellMoveThreadPoolExecutor Completed tasks : " + cherwellMoveThreadPoolExecutor.getCompletedTaskCount()+" Waiting for a second !! ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executor.execute(r);
}
});
}
}
I'm using this during a process running for multiple customers. For each customer new threadpool will be initialized and threads will be running.
Below is the code where I'm using the threadpool.
for (Object[] objects : relationshipList) {
CherwellRelationshipMoveThread relationshipThread = new CherwellRelationshipMoveThread(objects,
this.customerId, sb, credential,mainCIId,moveUniqueId,this.startTime);
CompletableFuture<?> future = CompletableFuture.runAsync(relationshipThread,
MoveToCherwellThreadPool.cherwellMoveThreadPoolExecutor);
crelationshipList.add(future);
}
crelationshipList.forEach(CompletableFuture::join);
This thread will be created for multiple customers. I'm giving an option to terminate this job in UI. On click of stop process I need to stop/kill only the threads running for that particular customer and other customer's thread shouldn't be harmed and should be keep running.
On click of stop process from UI I'm calling a service where inside the service my code will be
MoveToCherwellThreadPool.cherwellMoveThreadPoolExecutor.shutdownNow();
I'm calling shutdownNow() on the ThreadPoolExecutor.
This is killing all the threads of all the customers. I don't want to kill all the customers process, but only for the customer where I'll click on stop process.
This code doesn't maintain any mapping from a tenant to a thread pool, there's only one static reference to a ThreadPoolExecutor. Each time initiateCherwellMoveThreadPool is called, any existing executor will be replaced with a new one, and the existing one isn't shut down, so it will leak resources. As a result, this will execute tasks from multiple tenants in the same thread pool.
This code is also not thread safe. It's possible (if unlikely) that a thread could schedule a task on a newly-created executor, or even shut it down, before setRejectedExecutionHandler is called.
If you need a separate executor per tenant, this will need to be implemented. A good option might be to use a ConcurrentHashMap with customerId keys and ThreadPoolExecutor values, for example (logging omitted for brevity):
public class MoveToCherwellThreadPool {
public static ConcurrentMap<String, ThreadPoolExecutor> cherwellMoveThreadPoolExecutors = new ConcurrentHashMap<>();
public static ThreadPoolExecutor getCherwellMoveThreadPool(String customerId) {
return cherwellMoveThreadPoolExecutors.computeIfAbsent(customerId, id -> {
BlockingQueue<Runnable> q = new LinkedBlockingQueue<Runnable>(100000);
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 20, TimeUnit.SECONDS, q);
executor.setRejectedExecutionHandler(new RejectedExecutionHandler() { /*...*/ });
return executor;
});
}
public static List<Runnable> stopCherwellMoveTheadPool(String customerId) {
if (cherwellMoveThreadPoolExecutors.containsKey(customerId)) {
return cherwellMoveThreadPoolExecutors.get(customerId).shutdownNow();
}
return Collections.emptyList();
}
}
This can be used like this:
CompletableFuture<?> future = CompletableFuture.runAsync(relationshipThread,
MoveToCherwellThreadPool.getCherwellMoveThreadPool(customerId));
It's also important to realise that calling shutdownNow can only attempt to cancel currently executing tasks, and "does not wait for actively executing tasks to terminate":
This implementation cancels tasks via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
The code implementing CherwellRelationshipMoveThread isn't shown, so this may or may not be the case.
I am working on executor thread pools to check if any object has been inserted into a blocking queue. If any object has been inside of the queue, one thread wakes up from the pool and take object from the queue, send it to some class to process.
But im confused at using executor threads such as below. When I am using them inside a for loop, processes works fast as I expected but it looks like something wrong. When I take executors out inside of the for loop, processes gets slow. Is this logic correct?
Rest Class
#RestController
public class FraudRestController {
#Autowired
private CoreApplication core;
//LOGIC HERE
....
core.addMesageToQueue(rbtran, type);
}
Message Add To Queue
public static void addMessageToQueue(TCPRequestMessage message) throws InterruptedException {
jobQueue.put(message);
}
Executor Threads To Listen Queue in Core Class
ExecutorService consumers = Executors.newFixedThreadPool(THREAD_SIZE);
//Core Inits in here
#PostConstruct
public void init() {
//LOGIC
...
//<---THIS BLOCK----->
for (int i = 0; i < THREAD_SIZE; i++) { //<---- This For Loop
consumers.submit(() -> {
while (true)
sendMessageToServer();
});
}
//<---THIS BLOCK----->
}
Send Message Function
private void sendMessageToServer() throws Exception {
//LOGIC
...
if (host.isActive()) {
TCPRequestMessage message = jobQueue.take();
}
This will create a thread pool for you of the size that you pass.
ExecutorService consumers = Executors.newFixedThreadPool(THREAD_SIZE);
This means now there are THREAD_SIZE number of threads waiting on a queue. This queue created is a LinkedBlockingQueue. This queue has the property of making the threads wait on it if it is empty or full.
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
If a task is submitted to a pool, at that time if the queue is full, the task wont be submitted. In our case since we did not mention the size, so the size here is Integer.MAX_VALUE
If the queue is empty, the threads in the pool will be waiting for the task to be inserted in the queue.
When the ExecutorService's submit method is called.
Internally, the task is submitted into the queue boolean offer(E e); of the LinkedBlockingQueue.
I believe based on this, you can may be re design what you are implementing.
I need to send a email during registration process , so for this reason i am using Java Mail API , this is working fine , but observed that
the email process is taking nearly 6 seconds (which is too long ) so Ajax call making the user wait too long for response
so for this reason i have decided to use background thread for sending email so the user need not wait for the Ajax call response (Jersey REST Web Service call)
My question is it a good practice to creating threads in a webapplication for every request ??
#Path("/insertOrUpdateUser")
public class InsertOrUpdateUser {
final static Logger logger = Logger.getLogger(InsertOrUpdateUser.class);
#GET
#Consumes("application/text")
#Produces("application/json")
public String getSalesUserData(#QueryParam(value = "empId") String empId
)
throws JSONException, SQLException {
JSONObject final_jsonobject = new JSONObject();
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new Runnable() {
public void run() {
try {
SendEmailUtility.sendmail(emaildummy);
} catch (IOException e) {
logger.error("failed",e);
}
}
});
}
} catch (SQLException e) {
} catch (Exception e) {
}
finally {
}
return response;
}
}
And this is my Utility class for sending email
public class SendEmailUtility
{
public static String sendmail(String sendto)
throws IOException
{
String result = "fail";
Properties props_load = getProperties();
final String username = props_load.getProperty("username");
final String password = props_load.getProperty("password");
Properties props_send = new Properties();
props_send.put("mail.smtp.auth", "true");
props_send.put("mail.smtp.starttls.enable", "true");
props_send.put("mail.smtp.host", props_load.getProperty("mail.smtp.host"));
props_send.put("mail.smtp.port", props_load.getProperty("mail.smtp.port"));
Session session = Session.getInstance(props_send,
new javax.mail.Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(username, password);
}
});
try {
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(props_load.getProperty("setFrom")));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(sendto));
message.setText("Some Text to be send in mail");
Transport.send(message);
result = "success";
} catch (MessagingException e) {
result = "fail";
logger.error("Exception Occured - sendto: " + sendto, e);
}
return result;
}
}
Could you please let me know if this is best practice to do in a web application ??
There are host of ways you can handle it, so it all depends on whether your application server has that much resources (memory, threads etc.) to handle your implementation, so it makes you best person to decide on which approach to go.
As such it is not bad practice to spawn parallel threads for doing something if it is justified by design, but typically you should go with controlled threads.
Please note that whether you use newSingleThreadExecutor() or newFixedThreadPool(nThreads), under-the-hoods there will always be a ThreadPoolExecutor object created.
My recommendation will be to use seconds option in below list i.e. "Controlled number of threads", and in that specify max thread count as you see fir.
One thread for each request
In this approach one thread will be created for each incoming request from GUI, so if you are getting 10 requests for inserting/updating user then 10 threads will be spawned which will send emails.
Downside of this approach is that there is no control on number of threads so you can end with StackOverflowException or may be memory issue.
Please make sure to shutdown your executor service else you will end up wasting JVM resources.
// inside your getSalesUserData() method
ExecutorService emailExecutor = Executors.newSingleThreadExecutor();
emailExecutor.execute(new Runnable() {
#Override
public void run() {
try {
SendEmailUtility.sendmail(emaildummy);
} catch (IOException e) {
logger.error("failed", e);
}
}
});
emailExecutor.shutdown(); // it is very important to shutdown your non-singleton ExecutorService.
Controlled number of threads
In this approach, some pre-defined number of threads will be present and those will process your email sending requirement. In below example I am starting a thread pool with max of 10 threads, then I am using a LinkedBlockingQueue implementation so this will ensure that if there are more than 10 requests and currently all my 10 threads are busy then excess of requests will be queued and not lost, this is the advantage you get with LinkedBlockingQueue implementation of Queue.
You can initialize you singleton ThreadPoolExecutor upon application server start, if there are no requests then no threads will be present so it is safe to do so. In fact I use similar configuration for my prod application.
I am using time to live seconds as 1 seconds so if a thread is ideal in JVM for more than 1 seconds then it will die.
Please note that since same thread pool is used for processing all you requests, so it should be singleton and do not shutdown this thread pool else your tasks will never be executed.
// creating a thread pool with 10 threads, max alive time is 1 seconds, and linked blocking queue for unlimited queuing of requests.
// if you want to process with 100 threads then replace both instances of 10 with 100, rest can remain same...
// this should be a singleton
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
// inside your getSalesUserData() method
executor.execute(new Runnable() {
#Override
public void run() {
try {
SendEmailUtility.sendmail(emaildummy);
} catch (IOException e) {
logger.error("failed", e);
}
}
});
Java's default cached thread pool
This approach is much like above, only that Java will initialize the ThreadPoolExecutor for you as ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
Here max number of threads will be Integer.MAX_VALUE, so threads will be created as needed and time to live will be 60 seconds.
If you want to use this way then below is the way.
// this should be a singleton
ExecutorService emailExecutor = Executors.newCachedThreadPool();
// from you getSalesUserData() method
emailExecutor.execute(new Runnable() {
#Override
public void run() {
try {
SendEmailUtility.sendmail(emaildummy);
} catch (IOException e) {
logger.error("failed", e);
}
}
});
Manually creating of ExecutorService on java web serer is bad idea. In your implementation for each request you create 10 threads.
Better solution is to use ManagedExecutorService (example) if you work with JEE7 or ThreadPoolTaskExecutor if you work with Spring(docs).
If you work with Tomcat you should read this thread.
The best practice is to use a single ExecutorService to provide a thread pool for all requests. You probably want to configure the ExecutorService with a non-zero, but limited, number of threads.
The idea here is that you will have some threads that are reused throughout the lifetime of the application. You get the added benefit that if there is a temporary slowdown (or halt) in sending emails, you don't end up with a growing number of threads Instead, you end up with a growing number of pieces of work (emails to send) to be executed, which is much less resource intensive than extra threads.
I am using Java EmailSender class.
I simply started a new thread to send mail because it was blocking the main thread and I was getting Time out an exception.
String link = "http://localhost:PORT/api/v1/registration/confirm?token=" +token;
//Sending mail in thread beacause it block main thread
new Thread(
() -> emailSender.sendMail(request.getEmail(),buildEmail(request.getFirstName(),
link))).start();
Among all my tasks, I have some that must be processed serially (they can never run concurrently and they must be processed in order).
I achieved that creating a separated thread pool with a single thread for each group of tasks that must be executed serially. It works but I don't have the resources for that. I don't control the number of groups, so I might end up with a ridiculous number of threads running simultaneously.
Is there any way I can accomplish that with a single thread pool? Is there a thread pool with multiple blocking queues where I could ensure serial execution for each queue?
EDIT:
Just emphasizing what I've said in my second paragraph: I've solved this with a single threaded thread pool for each group of tasks that must be executed serially. I can't go on with this solution, though. There are way too many groups and I can't have all these threads.
I've found this related question, but since it is not very recent, I still created mine. All I'm doing is trying to avoid reinventing the wheel, but it seems I don't have a choice.
Does Java have an indexable multi-queue thread pool?
If you maintain a queue for each group, you can pull items off each queue and feed them into a thread pool. The code below won't prioritize any one group, it just pulls them in a round-robin fashion. If you need to add prioritization you should easily be able to. The following code will round-robin 4 groups using two threads (plus the thread managing the queue). You can use another queue mechanism. I typically use LinkedBlockingQueue for situations where I want to wait for items to be placed on the queue by another thread, which probably is not what you want - so I'm polling instead of calling take(). Take is the call that waits.
private Future group1Future = null;
private Future group2Future = null;
private Future group3Future = null;
private Future group4Future = null;
private LinkedBlockingQueue<Callable> group1Queue
= new LinkedBlockingQueue<>();
private LinkedBlockingQueue<Callable> group2Queue
= new LinkedBlockingQueue<>();
private LinkedBlockingQueue<Callable> group3Queue
= new LinkedBlockingQueue<>();
private LinkedBlockingQueue<Callable> group4Queue
= new LinkedBlockingQueue<>();
private ExecutorService executor = Executors.newFixedThreadPool(2);
public void startProcessing() {
while (true) {
if (group1Future != null && group1Future.isDone()) {
if (group1Queue.peek() != null) {
group1Future = executor.submit(group1Queue.poll());
}
}
if (group2Future != null && group1Future.isDone()) {
if (group2Queue.peek() != null) {
group2Future = executor.submit(group2Queue.poll());
}
}
if (group3Future != null && group3Future.isDone()) {
if (group3Queue.peek() != null) {
group3Future = executor.submit(group3Queue.poll());
}
}
if (group4Future != null && group4Future.isDone()) {
if (group4Queue.peek() != null) {
group4Future = executor.submit(group4Queue.poll());
}
}
}
}
If a task for that group is not complete, it will skip to the next group. No more than two groups will be processed at a time and no single group will ever run more than one task. The queues will enforce ordered execution.
Akka, as suggested by #SotiriosDelimanolis and #AlexeiKaigorodov seems promising, as well as #Dodd10x second answer, which certainly solves the problem. The only downside is that I'd have to code my own polling strategy to make sure my tasks are eventually added to the executor (like the infinite loop in his example).
On the other hand, the Striped Executor Service suggested by #OldCurmudgeon exactly matches my problem and works out of the box simply as a custom ExecutorService.
This magical thread pool would ensure that all Runnables with the same stripeClass would be executed in the order they were submitted, but StripedRunners with different stripedClasses could still execute independently. He wanted to use a relatively small thread pool to service a large number of Java NIO clients, but in such a way that the runnables would still be executed in-order.
There is even a comment about using a single threaded thread pool for each group (stripe), as it was suggested here:
Several suggestions were made, such as having a SingleThreadExecutor for each stripeClass. However, that would not satisfy the requirement that we could share the threads between connections.
I see this as the best solution for its simplicity and ease of use.
I recently answered a question about a "serial task queue" with a basic implementation as demonstration here. I imagine you have been using a similar solution. It is relatively easy to adapt the implementation to use a map of task lists and still share one (fixed size) executor.
The Striped Executor Service you mention is the better solution, but I show the adapted implementation here to demonstrate decoupling the task queue(s) from the executor. The implementation uses a callback and therefor has no need to do polling or signalling. Since a "critical (stop the world) section" is used, the map with task queues can clean itself: no tasks queued means empty map. Downside of the "critical section" is that throughput is limited: only so many tasks can be added and removed per second.
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
// Copied and updated from https://stackoverflow.com/a/32916943/3080094
public class SerialTaskQueues {
public static void main(String[] args) {
// test the serial task execution using different groups
ExecutorService executor = Executors.newFixedThreadPool(2);
SerialTaskQueues tq = new SerialTaskQueues(executor);
try {
// test running the tasks one by one
tq.add(new SleepSome("1", 30L));
Thread.sleep(5L);
tq.add(new SleepSome("2", 20L));
tq.add(new SleepSome("1", 10L));
Thread.sleep(100L);
// all queues should be empty
System.out.println("Queue size 1: " + tq.size("1")); // should be empty
System.out.println("Queue size 2: " + tq.size("2")); // should be empty
tq.add(new SleepSome("1", 10L));
tq.add(new SleepSome("2", 20L));
// with executor pool size set to 2, task 3 will have to wait for task 1 to complete
tq.add(new SleepSome("3", 30L));
tq.add(new SleepSome("1", 20L));
tq.add(new SleepSome("2", 10L));
Thread.sleep(100L);
} catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdownNow();
}
}
// all lookups and modifications to the list must be synchronized on the list.
private final Map<String, GroupTasks> taskGroups = new HashMap<>();
// make lock fair so that adding and removing tasks is balanced.
private final ReentrantLock lock = new ReentrantLock(true);
private final ExecutorService executor;
public SerialTaskQueues(ExecutorService executor) {
this.executor = executor;
}
public boolean add(String groupId, Runnable task) {
lock.lock();
try {
GroupTasks gt = taskGroups.get(groupId);
if (gt == null) {
gt = new GroupTasks(groupId);
taskGroups.put(groupId, gt);
}
gt.tasks.add(task);
} finally {
lock.unlock();
}
runNextTask(groupId);
return true;
}
/* Utility method for testing. */
public void add(SleepSome sleepTask) {
add(sleepTask.groupId, sleepTask);
}
private void runNextTask(String groupId) {
// critical section that ensures one task is executed.
lock.lock();
try {
GroupTasks gt = taskGroups.get(groupId);
if (gt.tasks.isEmpty()) {
// only cleanup when last task has executed, prevent memory leak
if (!gt.taskRunning.get()) {
taskGroups.remove(groupId);
}
} else if (!executor.isShutdown() && gt.taskRunning.compareAndSet(false, true)) {
executor.execute(wrapTask(groupId, gt.taskRunning, gt.tasks.remove(0)));
}
} finally {
lock.unlock();
}
}
private CallbackTask wrapTask(final String groupId, final AtomicBoolean taskRunning, Runnable task) {
return new CallbackTask(task, new Runnable() {
#Override
public void run() {
if (!taskRunning.compareAndSet(true, false)) {
System.out.println("ERROR: programming error, the callback should always run in execute state.");
}
runNextTask(groupId);
}
});
}
/** Amount of (active) task groups. */
public int size() {
int size = 0;
lock.lock();
try {
size = taskGroups.size();
} finally {
lock.unlock();
}
return size;
}
public int size(String groupId) {
int size = 0;
lock.lock();
try {
GroupTasks gt = taskGroups.get(groupId);
size = (gt == null ? 0 : gt.tasks.size());
} finally {
lock.unlock();
}
return size;
}
public Runnable get(String groupId, int index) {
Runnable r = null;
lock.lock();
try {
GroupTasks gt = taskGroups.get(groupId);
r = (gt == null ? null : gt.tasks.get(index));
} finally {
lock.unlock();
}
return r;
}
public Runnable remove(String groupId, int index) {
Runnable r = null;
lock.lock();
try {
GroupTasks gt = taskGroups.get(groupId);
r = gt.tasks.remove(index);
// similar to runNextTask - cleanup if there are no tasks (running) for the group
if (gt.tasks.isEmpty() && !gt.taskRunning.get()) {
taskGroups.remove(groupId);
}
} finally {
lock.unlock();
}
return r;
}
/* Helper class for the task-group map. */
class GroupTasks {
final List<Runnable> tasks = new LinkedList<Runnable>();
// atomic boolean used to ensure only 1 task is executed at any given time
final AtomicBoolean taskRunning = new AtomicBoolean(false);
final String groupId;
GroupTasks(String groupId) {
this.groupId = groupId;
}
}
// general callback-task, see https://stackoverflow.com/a/826283/3080094
static class CallbackTask implements Runnable {
private final Runnable task, callback;
public CallbackTask(Runnable task, Runnable callback) {
this.task = task;
this.callback = callback;
}
#Override
public void run() {
try {
task.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
callback.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// task that just sleeps for a while
static class SleepSome implements Runnable {
static long startTime = System.currentTimeMillis();
private final String groupId;
private final long sleepTimeMs;
public SleepSome(String groupId, long sleepTimeMs) {
this.groupId = groupId;
this.sleepTimeMs = sleepTimeMs;
}
#Override public void run() {
try {
System.out.println(tdelta(groupId) + "Sleeping for " + sleepTimeMs + " ms.");
Thread.sleep(sleepTimeMs);
System.out.println(tdelta(groupId) + "Slept for " + sleepTimeMs + " ms.");
} catch (Exception e) {
e.printStackTrace();
}
}
private String tdelta(String groupId) { return String.format("% 4d [%s] ", (System.currentTimeMillis() - startTime), groupId); }
}
}
A single thread executor will do
ExecutorService executorService = Executors.newSingleThreadExecutor();
Which internally uses a ThreadPoolExecutor with a LinkedBlockingQueue
new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()))
So you can use this for your sequential stuff and probably use a multi-threaded executor service for concurrent tasks
Look into Java's built-in thread executor service.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html
There is a single thread executor that will process each task synchronously.
In response to the comments section:
Please read the API before you say this won't work.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor()
Creates an Executor that uses a single worker thread operating off an unbounded queue. (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.) Tasks are guaranteed to execute sequentially, and no more than one task will be active at any given time. Unlike the otherwise equivalent newFixedThreadPool(1) the returned executor is guaranteed not to be reconfigurable to use additional threads.
Note: is states they are guaranteed to execute sequentially.
EDIT:
Now that I understand your question better, I have an idea you could try. If you maintain a queue for each group, you can pull items off each queue and feed them into a thread pool. The code below won't prioritize any one group, it just pulls them in a round robbing fashion. If you need to add prioritization you should easily be able to. The following code will round robbing 4 groups using two threads (plus the thread managing the queue). You can use another queue mechanism. I typically use LinkedBlockingQueue for situations where I want to wait for items to be placed on the queue by another thread, which probably is not what you want - which is why I'm polling instead of calling take(). Take is the call that waits.
private Future group1Future = null;
private Future group2Future = null;
private Future group3Future = null;
private Future group4Future = null;
private LinkedBlockingQueue<Callable> group1Queue
= new LinkedBlockingQueue<>();
private LinkedBlockingQueue<Callable> group2Queue
= new LinkedBlockingQueue<>();
private LinkedBlockingQueue<Callable> group3Queue
= new LinkedBlockingQueue<>();
private LinkedBlockingQueue<Callable> group4Queue
= new LinkedBlockingQueue<>();
private ExecutorService executor = Executors.newFixedThreadPool(2);
public void startProcessing() {
while (true) {
if (group1Future != null && group1Future.isDone()) {
if (group1Queue.peek() != null) {
group1Future = executor.submit(group1Queue.poll());
}
}
if (group2Future != null && group1Future.isDone()) {
if (group2Queue.peek() != null) {
group2Future = executor.submit(group2Queue.poll());
}
}
if (group3Future != null && group3Future.isDone()) {
if (group3Queue.peek() != null) {
group3Future = executor.submit(group3Queue.poll());
}
}
if (group4Future != null && group4Future.isDone()) {
if (group4Queue.peek() != null) {
group4Future = executor.submit(group4Queue.poll());
}
}
}
}
If a task for that group is not complete, it will skip to the next group. No more than two groups will be processed at a time and no single group will ever run more than one task. The queues will enforce ordered execution.
What you need is not a special executor, but means to express dependencies between tasks. Instead of a group of tasks which must be executed serially, think of a task which, at the end of execution, sends a signal to the next task, thus starting its execution. So your task can be coded as an actor which waits for allowing signal to start execution. Consider Akka or any other actor library (e.g. mine df4j).
There is no standard implementation of thread pool with these requirements.
Striped Executor Service mentioned in the accepted answer is a good substitute.
The disadvantages I see are: multiple queues (no way to limit queue capacity, or maintain a submission order), thread per stripe (if you have a lot of stripes, your thread pool will grow).
I decided to create similar implementation with single queue:
GitHub - TaggedThreadPoolExecutor.java
It implements standard ExecutorService interface, maintain single queue, takes a maximum number of threads as a parameter, support different rejection policies (similar to standard ThreadPoolExecutor), unlike ThreadPoolExecutor it starts new thread not when queue is full, but when new task is submitted.
You could maintain a bunch of queues (List or a Map of queues). Each queue hold a task for that specific class, and have a background running thread which will dequeue tasks from each queue serially and submit them on a separate threadpool executor which could be a bigger in size in terms of number of threads!
I have a single thread producer which creates some task objects which are then added into an ArrayBlockingQueue (which is of fixed size).
I also start a multi-threaded consumer. This is build as a fixed thread pool (Executors.newFixedThreadPool(threadCount);). I then submit some ConsumerWorker intances to this threadPool, each ConsumerWorker having a refference to the above mentioned ArrayBlockingQueue instance.
Each such Worker will do a take() on the queue and deal with the task.
My issue is, what's the best way to have a Worker know when there won't be any more work to be done. In other words, how do I tell the Workers that the producer has finished adding to the queue, and from this point on, each worker should stop when he sees that the Queue is empty.
What I've got now is a setup where my Producer is initialized with a callback which is triggered when he finishes it's job (of adding stuff to the queue). I also keep a list of all the ConsumerWorkers I've created and submitted to the ThreadPool. When the Producer Callback tells me that the producer is done, I can tell this to each of the workers. At this point they should simply keep checking if the queue is not empty, and when it becomes empty they should stop, thus allowing me to gracefully shutDown the ExecutorService thread pool. It's something like this
public class ConsumerWorker implements Runnable{
private BlockingQueue<Produced> inputQueue;
private volatile boolean isRunning = true;
public ConsumerWorker(BlockingQueue<Produced> inputQueue) {
this.inputQueue = inputQueue;
}
#Override
public void run() {
//worker loop keeps taking en element from the queue as long as the producer is still running or as
//long as the queue is not empty:
while(isRunning || !inputQueue.isEmpty()) {
System.out.println("Consumer "+Thread.currentThread().getName()+" START");
try {
Object queueElement = inputQueue.take();
//process queueElement
} catch (Exception e) {
e.printStackTrace();
}
}
}
//this is used to signal from the main thread that he producer has finished adding stuff to the queue
public void setRunning(boolean isRunning) {
this.isRunning = isRunning;
}
}
The problem here is that I have an obvious race condition where sometimes the producer will finish, signal it, and the ConsumerWorkers will stop BEFORE consuming everything in the queue.
My question is what's the best way to synchronize this so that it all works ok? Should I synchronize the whole part where it checks if the producer is running plus if the queue is empty plus take something from the queue in one block (on the queue object)? Should I just synchronize the update of the isRunning boolean on the ConsumerWorker instance? Any other suggestion?
UPDATE, HERE'S THE WORKING IMPLEMENTATION THAT I'VE ENDED UP USING:
public class ConsumerWorker implements Runnable{
private BlockingQueue<Produced> inputQueue;
private final static Produced POISON = new Produced(-1);
public ConsumerWorker(BlockingQueue<Produced> inputQueue) {
this.inputQueue = inputQueue;
}
#Override
public void run() {
//worker loop keeps taking en element from the queue as long as the producer is still running or as
//long as the queue is not empty:
while(true) {
System.out.println("Consumer "+Thread.currentThread().getName()+" START");
try {
Produced queueElement = inputQueue.take();
Thread.sleep(new Random().nextInt(100));
if(queueElement==POISON) {
break;
}
//process queueElement
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Consumer "+Thread.currentThread().getName()+" END");
}
}
//this is used to signal from the main thread that he producer has finished adding stuff to the queue
public void stopRunning() {
try {
inputQueue.put(POISON);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This was inspired heavily by JohnVint's answer below, with only some minor modifications.
=== Update due to #vendhan's comment.
Thank you for your obeservation. You are right, the first snippet of code in this question has (amongst other issues) the one where the while(isRunning || !inputQueue.isEmpty()) doesn't really make sense.
In my actual final implementation of this, I do something which is closer to your suggestion of replacing "||" (or) with "&&" (and), in the sense that each worker (consumer) now only checks if the element he's got from the list is a poison pill, and if so stops (so theoretically we can say that the worker has to be running AND the queue must not be empty).
You should continue to take() from the queue. You can use a poison pill to tell the worker to stop. For example:
private final Object POISON_PILL = new Object();
#Override
public void run() {
//worker loop keeps taking en element from the queue as long as the producer is still running or as
//long as the queue is not empty:
while(isRunning) {
System.out.println("Consumer "+Thread.currentThread().getName()+" START");
try {
Object queueElement = inputQueue.take();
if(queueElement == POISON_PILL) {
inputQueue.add(POISON_PILL);//notify other threads to stop
return;
}
//process queueElement
} catch (Exception e) {
e.printStackTrace();
}
}
}
//this is used to signal from the main thread that he producer has finished adding stuff to the queue
public void finish() {
//you can also clear here if you wanted
isRunning = false;
inputQueue.add(POISON_PILL);
}
I'd send the workers a special work packet to signal that they should shut down:
public class ConsumerWorker implements Runnable{
private static final Produced DONE = new Produced();
private BlockingQueue<Produced> inputQueue;
public ConsumerWorker(BlockingQueue<Produced> inputQueue) {
this.inputQueue = inputQueue;
}
#Override
public void run() {
for (;;) {
try {
Produced item = inputQueue.take();
if (item == DONE) {
inputQueue.add(item); // keep in the queue so all workers stop
break;
}
// process `item`
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
To stop the workers, simply add ConsumerWorker.DONE to the queue.
In your code-block where you attempt to retrive element from the queue , use poll(time,unit) instead of the take().
try {
Object queueElement = inputQueue.poll(timeout,unit);
//process queueElement
} catch (InterruptedException e) {
if(!isRunning && queue.isEmpty())
return ;
}
By specifying appropriate values of timeout , you ensure that threads wont keep blocking in case there is a unfortunate sequence of
isRunning is true
Queue becomes empty , so threads enter blocked wait ( if using take()
isRunning is set to false
Can not we do it using a CountDownLatch, where the size is the number of records in the producer. And every consumer will countDown after process a record. And its crosses the awaits() method when all tasks finished. Then stop all ur consumers. As all records are processed.
There are a number of strategies you could use, but one simple one is to have a subclass of task that signals the end of the job. The producer doesn't send this signal directly. Instead, it enqueues an instance of this task subclass. When one of your consumers pulls off this task and executes it, that causes the signal to be sent.
I had to use a multi-threaded producer and a multi-threaded consumer.
I ended up with a Scheduler -- N Producers -- M Consumers scheme, each two communicate via a queue (two queues total). The Scheduler fills the first queue with requests to produce data, and then fills it with N "poison pills". There is a counter of active producers (atomic int), and the last producer that receives the last poison pill sends M poison pills to the consumer queue.