Java using ExecutorService,CompletionService,BlockingQueue,and Observer correctly? - java

So, I'm pretty new to multi-threading and have been using this idea in all my programs lately. Before I start using it more I really want to make sure it is a correct efficient way to implement multi-threading using the Executor,CompletionService and a BlockingQueue plus an Observer. I'll provide example code below but let me first quickly explain how I think it works and maybe that will help.
The first thing I have is a BlockingQueue all tasks are added to this queue via an add(Task task) method. Upon creation of the class the run method is called with a while(true) calling take on the queue blocking until something gets added to the task queue.
Once something gets added to the queue inside the run() queue.take() returns the item on queue. Then I take that item and pass it to WorkerThread class that does stuff on it. That workerThread is added to the CompletionService pool which handles the waiting for a thread to finish.
Ok now comes the part i'm not sure is correct. I also have an inner class that implements runnable and is started when the class is initialized. Its job is to loop forever calling pool.take(). So, this essentially waits for one of the WorkerThreads to complete. I let the completion service handle this. Once the take() gets a value the inner class passes it to a notify observer method.
Is this okay implementation.? It concerns me a bit that there is the main classes run with a while(true) looping on task queue and an inner class also looping waiting on pool to receive a result from WorkerThread?
Here is an example implementation. What you think?
public class HttpSchedulerThreaded extends Observable implements Runnable {
private ArrayList<Object> list;//holds [0]=VULNINFO, [1]=REQUESTBUILDER OBJECT
protected static Logger logger = Logger.getLogger(HttpScheduler.class.getName());
private CompletionService<VulnInfo> pool;
private ExecutorService executor ;
private Thread responseWorkerThread;
private HttpSchedulerWorker schedulerWorker;
private boolean shouldRun = true;
private CountDownLatch doneSignal;
private String[] vulnClassesIgnoreRedirect;
private boolean followRedirects;
private boolean runJavascriptInResponse;
private boolean isSSL;
private int numThreadsInPool;
private BlockingQueue<VulnInfo> queue;
private boolean isRunning ;
public HttpSchedulerThreaded(int numThreads)
{
numThreadsInPool = numThreads;
executor = Executors.newFixedThreadPool(numThreads);
doneSignal = new CountDownLatch(numThreads);
pool = new ExecutorCompletionService<VulnInfo>(executor);
schedulerWorker = new HttpSchedulerWorker();
responseWorkerThread = new Thread(schedulerWorker);
queue = new LinkedBlockingQueue<VulnInfo>();
}
public HttpSchedulerThreaded()
{
numThreadsInPool = 1;
executor = Executors.newFixedThreadPool(1);
doneSignal = new CountDownLatch(1);
pool = new ExecutorCompletionService<VulnInfo>(executor);
schedulerWorker = new HttpSchedulerWorker();
responseWorkerThread = new Thread(schedulerWorker);
queue = new LinkedBlockingQueue<VulnInfo>();
}
public void setThreadCount(int numThreads)
{
if(!isRunning){
executor = Executors.newFixedThreadPool(numThreads);
doneSignal = new CountDownLatch(numThreads);
pool = new ExecutorCompletionService<VulnInfo>(executor);
numThreadsInPool = numThreads;
}
}
public void start()
{
if(!isRunning){
responseWorkerThread.start();
new Thread(this).start();
isRunning = true;
}
}
public void add(VulnInfo info) {
queue.add(info);
}
#Override
public void run() {
// TODO Auto-generated method stub
while(shouldRun)
{
try {
VulnInfo info = queue.take();
Callable<VulnInfo> worker = new HttpSchedulerRequestSender(info,followRedirects,runJavascriptInResponse,vulnClassesIgnoreRedirect,doneSignal);
//System.out.println("submitting to pooler: " + info.getID());
pool.submit(worker);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* Inner class of proxy is a worker thread blocks until the pool has transactions complete as soon as they
* are complete it will send them to server for completion.
* #author Steve
*
*/
class HttpSchedulerWorker implements Runnable{
public void run() {
// TODO Auto-generated method stub
while(true)
{
VulnInfo vulnInfo = null;
try {
//System.out.println("taking finished request");
Future<VulnInfo> tmp = pool.take();
// Future<VulnInfo> tmp = pool.poll();
if(tmp != null)
vulnInfo = tmp.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(vulnInfo != null)
{
//System.out.println("updating all observers: " + vulnInfo.getID());
updateObservers(vulnInfo);
}
}
}
}

From my experience, your solution seems to be okay. I have three comments/suggestions:
Once you create a new thread of execution responseWorkerThread = new Thread(schedulerWorker) and responseWorkerThread.start(), you've essentially broken apart those two loops. This part looks okay. You do seem to be using the Executors API correctly, but it does look like you may need some more code for stopping the HttpScheduledWorker thread and for shutting down the ExecutionCompletionService as part of the HttpSchedulerThreaded class.
I'm not sure that your use of queue is really necessary. ExecutionCompletionService already uses a BlockingQueue to manage the tasks which are submitted to it.
Your "question" may be a better fit over at the beta Code Review site.

Related

Custom thread pool implementation in java

For leaning purpose i am trying to implement my own thread pool in java. Below is what i have implemented. I have few questions about this implementation:
Although i am using BlockingQueue like built in java Executors expect us to provide Runnable objects (through execute method). But in my case i feel like i can create any object instead of Runnable. So then why does Java executors expect Runnable, i tried looking into the source code but could not figure it out yet.
Is there anything else wrong with this primitive implementation ?
Please find the code.
public class CustomThreadPool {
private final BlockingQueue<Runnable> blockingQueue;
private final Worker[] workers;
public CustomThreadPool(final int numOfThreads) {
blockingQueue = new LinkedBlockingQueue<>();
workers = new Worker[numOfThreads];
for (int i = 0; i < numOfThreads; i++) {
workers[i] = new Worker();
workers[i].start();
}
}
public void execute(final Runnable task) {
blockingQueue.add(task);
}
public void shutdownImmediately() {
for (int i = 0; i < workers.length; i++) {
workers[i].shutdownSignal = true;
workers[i] = null;
}
}
private class Worker extends Thread {
private Runnable taskToPerform = null;
boolean shutdownSignal = false;
#Override
public void run() {
while(true && !shutdownSignal) {
taskToPerform = blockingQueue.poll();
if (taskToPerform != null) {
taskToPerform.run();
}
if(shutdownSignal) {
break;
}
}
}
}
public static void main(String[] args) throws Exception {
final CustomThreadPool threadPool = new CustomThreadPool(5);
for (int i = 0; i < 20; i++) {
threadPool.execute(() -> System.out.println(Thread.currentThread().getName()));
}
Thread.sleep(1*1000);
threadPool.shutdownImmediately();
}
}
Executor expects Runnable or Callable because it will call run or call method of these interfaces when it is running the tasks you submitted.
In Your implementation You don't use blocking aspects of BlockingQueue. Your thread pool threads will spin constantly(take cpu time) on Your while(true && !shutdownSignal) loop when there is no task exists in Your queue. Because poll() method is not blocking. And this not something You would want when implementing a thread pool.
You should use one of the blocking methods instead of poll().
You can use poll(long timeout,TimeUnit unit) method which takes time out parameter. In this case if You call Your shutdownImmediately method while any thread pool thread waiting on this call. They will wait for the time out duration and poll will return null to them They will see shutdownSignal is being set and get out of the loop. You can also call interrupt method If You don't want them to wait for the timeout.
// in run method
try {
taskToPerform = blockingQueue.poll(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
break; // this thread is interrupted. Time to leave this loop
}
// in shutdownImmediately method
workers[i].shutdownSignal = true;
// If You don't call interrupt, Threads will wait at max 5 sec for this case.
workers[i].interrupt();
workers[i] = null;
Or You can use take() method which blocks when there is nothing on the queue. But in this case You have to interrupt the threads that might be waiting on the take method call when You call Your shutdownImmediately method. Otherwise they will stuck at the take() call.
// in run method
try {
taskToPerform = blockingQueue.take();
} catch (InterruptedException e) {
break; // this thread is interrupted. Time to leave this loop
}
// in shutdownImmediately method
workers[i].shutdownSignal = true;
workers[i].interrupt(); // this is crucial for this case
workers[i] = null;

executor not executing threads from within a main thread

I have a Thread which runs always with while(true) loop and basically all it does is to add Runnable objects to an executor.
OrderExecutionThread:
public class OrderExecutionThread extends Thread implements Runnable {
final private static int ORDER_EXEC_THREADS_NUMBER = 10;
private boolean running = true;
private boolean flag = true;
private List<Order> firstSellsList = new ArrayList<>();
private List<Order> secondSellsList = new ArrayList<>();
private ManagedDataSource managedDataSource;
private ExecutorService executorService;
public OrderExecutionThread(ManagedDataSource managedDataSource) {
this.managedDataSource = managedDataSource;
this.executorService = Executors.newFixedThreadPool(ORDER_EXEC_THREADS_NUMBER);
}
#Override
public void run() {
while (running) {
if (!firstSellsList.isEmpty() && !firstBuysList.isEmpty()) {
initAndRunExecution(firstBuysList.get(0), firstSellsList.get(0));
}
}
private void initAndRunExecution(Order buy, Order sell) {
executorService.submit(new OrderExecution(buy, sell, managedDataSource));
}
}
I'm running this thread By doing this in my main class:
new Thread(orderExecutionThread).start();
The executor suppose to execute the OrderExecution runnable object which does this:
#Override
public void run() {
try {
connection = managedDataSource.getConnection();
makeExecution(sell, buy);
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (!connection.isClosed())
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
I know for sure that both lists are not empty and the initAndRunExecution is being called, however the order execution run method is not being called....
I know for sure that both lists are not empty and the initAndRunExecution is being called, however the order execution run method is not being called....
I suspect that this is a problem because your firstSellsList and firstBuysList are not synchronized collections. I suspect that other threads are adding to those lists but your OrderExecutionThread never sees the memory updates so just spins forever seeing empty lists. Whenever you share data between threads you need to worry about how the updates will be published and how the thread cache memory will be updated.
As #Fildor mentions in the comments, one solution would be to use a BlockingQueues instead of your Lists. The BlockQueue (for example LinkedBlockingQueue) is a synchronized class so this takes care of the memory sharing. An alternative benefit is that you don't have to do a spin-loop to watch for entries.
For example, your OrderExecutionThread might do something like:
private final BlockingQueue<Order> firstBuys = new LinkedBlockingQueue<>();
private final BlockingQueue<Order> firstSells = new LinkedBlockingQueue<>();
while (!Thread.currentThread().isInterrupted()) {
// wait until we get a buy
Order buy = firstBuys.take();
// wait until we get a sell
Order sell = firstSells.take();
initAndRunExecution(buy, sell);
}
This will wait until the lists get entries before running the orders.

Main thread hangs because of BlockingQueue's consumer (which I thought was on another thread)

I have a test that is blocking (first block of code). I have a few elements that are all working together. I have a blocking queue that I put events on to, then I have a consumer that takes them off and sends them to Amazon Kinesis. I am pretty sure that my test is getting blocked because the queue is blocking my consumer even though I thought it was running on a separate thread.
// Test.java
#Test
public void testWhileLoop() throws InterruptedException {
ArrayBlockingQueue<Event> testQ = new ArrayBlockingQueue<Event>(1024);
// mockKinesis is a mock at the class level.
KPLPoster kpl = new KPLPoster("TestStream", mockKinesis, testQ);
Event event = new Event("TestMessage", "TestPartition");
ListenableFuture<UserRecordResult> fakeReturn = Mockito.mock(ListenableFuture.class);
final AtomicInteger numberOfWhileLoops = new AtomicInteger();
Mockito.doAnswer(invocation -> {
numberOfWhileLoops.incrementAndGet();
return fakeReturn;
})
.when(mockKinesis)
.addUserRecord("TestStream", "TestPartition", ByteBuffer.wrap("TestMessage".getBytes()));
kpl.run(); // Hangs here
for(int i = 100; i > 0; i--){
testQ.put(event);
}
kpl.stop();
kpl = null;
assert(numberOfWhileLoops.toString()).equals("100");
}
Here is the run method of BaseKinesisPoster which my KPLPoster inherits. It should be noted that BaseKinesisPoster implements the Runnable interface.
//BaseKinesisPoster.java
#Override
public void run() {
shutdown = false;
while (!shutdown && !(Thread.currentThread().isInterrupted())) {
try {
this.runOnce();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}catch (Exception e){
e.printStackTrace();
}
}
}
Finally, here is part of my KPLPoster's (which extends BaseKinesisPoster) relevant runOnce() method.
// KPLPoster.java
#Override
protected void runOnce() throws Exception {
Event event = inputQueue.take();
//other stuff in my method
}
How do I make sure that blocking on my queue consumer doesn't block my test/main thread?
When you call
Thread.run();
it invokes the method called. Nothing special happens and the method is run in the current thread.
When you call
Thread.start();
This starts the thread which in turn calls run() in that new thread.
BTW Thread.stop() will throw an UnsupportedOperationException in Java 8. You shouldn't use it. You should allow it to finish naturally.

Blocking Queue Take() does not retrieve the item

I have the code below:
#Override
public boolean start() {
boolean b = false;
if (status != RUNNING) {
LOGGER.info("Starting Auto Rescheduler Process...");
try {
b = super.start();
final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("Rescheduler-Pool-%d").build();
ExecutorService exServ = Executors.newSingleThreadExecutor(threadFactory);
service = MoreExecutors.listeningDecorator(exServ);
} catch (Exception e) {
LOGGER.error("Error starting Auto Rescheduler Process! {}", e.getMessage());
LOGGER.debug("{}", e);
b = false;
}
} else {
LOGGER.info("Asked to start Auto Rescheduler Process but it had already started. Ignoring...");
}
return b;
}
The AutoRescheduler is the runnable below:
private class AutoScheduler implements Runnable {
private static final String DEFAULT_CONFIGURABLE_MINUTES_VALUE = "other";
private static final long DEFAULT_DELAY_MINUTES = 60L;
#Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
//BLOCKS HERE UNTIL A FINISHED EVENT IS PUT IN QUEUE
final FinishedEvent fEvent = finishedEventsQueue.take();
LOGGER.info("Received a finished Event for {} and I am going to reschedule it", fEvent);
final MyTask task = fEvent.getSource();
final LocalDateTime nextRunTime = caclulcateNextRightTime(task);
boolean b = scheduleEventService.scheduleEventANew(task, nextRunTime);
if (b) {
cronController.loadSchedule();
LOGGER.info("Rescheduled event {} for {}", task, nextRunTime);
}
} catch (InterruptedException e) {
LOGGER.error("Interrupted while waiting for a new finishedEventQueue");
Thread.currentThread().interrupt();
}
}
I see events being caught and put in the queue. Normally I then see them being rescheduled by the AutoReschduler
However from time to time I stop seeing them being rescheduled which leads me to believe that the reschedulingThread dies silently. After this happens no more events are taken from the queue until I restart the process (I have a GUI that allows me to call the stop() and start() methods of the public class). After I restart it though, the blocked events are rescheduled normally which means that they are in the queue indeed.
Does anyone have an idea?
EDIT
I have reproduced the error in Eclipse. The thread does not die (I have tested with the ExecutorService as well. However take() still does not take the item from the queue although it is placed there.

Editable queue of tasks running in background thread

I know this question was answered many times, but I'm struggling to understand how it works.
So in my application the user must be able to select items which will be added to a queue (displayed in a ListView using an ObservableList<Task>) and each item needs to be processed sequentially by an ExecutorService.
Also that queue should be editable (change the order and remove items from the list).
private void handleItemClicked(MouseEvent event) {
if (event.getClickCount() == 2) {
File item = listView.getSelectionModel().getSelectedItem();
Task<Void> task = createTask(item);
facade.getTaskQueueList().add(task); // this list is bound to a ListView, where it can be edited
Future result = executor.submit(task);
// where executor is an ExecutorService of which type?
try {
result.get();
} catch (Exception e) {
// ...
}
}
}
Tried it with executor = Executors.newFixedThreadPool(1) but I don't have control over the queue.
I read about ThreadPoolExecutor and queues, but I'm struggling to understand it as I'm quite new to Concurrency.
I need to run that method handleItemClicked in a background thread, so that the UI does not freeze, how can I do that the best way?
Summed up: How can I implement a queue of tasks, which is editable and sequentially processed by a background thread?
Please help me figure it out
EDIT
Using the SerialTaskQueue class from vanOekel helped me, now I want to bind the List of tasks to my ListView.
ListProperty<Runnable> listProperty = new SimpleListProperty<>();
listProperty.set(taskQueue.getTaskList()); // getTaskList() returns the LinkedList from SerialTaskQueue
queueListView.itemsProperty().bind(listProperty);
Obviously this doesn't work as it's expecting an ObservableList. There is an elegant way to do it?
The simplest solution I can think of is to maintain the task-list outside of the executor and use a callback to feed the executor the next task if it is available. Unfortunately, it involves synchronization on the task-list and an AtomicBoolean to indicate a task executing.
The callback is simply a Runnable that wraps the original task to run and then "calls back" to see if there is another task to execute, and if so, executes it using the (background) executor.
The synchronization is needed to keep the task-list in order and at a known state. The task-list can be modified by two threads at the same time: via the callback running in the executor's (background) thread and via handleItemClicked method executed via the UI foreground thread. This in turn means that it is never exactly known when the task-list is empty for example. To keep the task-list in order and at a known fixed state, synchronization of the task-list is needed.
This still leaves an ambiguous moment to decide when a task is ready for execution. This is where the AtomicBoolean comes in: a value set is always immediatly availabe and read by any other thread and the compareAndSet method will always ensure only one thread gets an "OK".
Combining the synchronization and the use of the AtomicBoolean allows the creation of one method with a "critical section" that can be called by both foreground- and background-threads at the same time to trigger the execution of a new task if possible. The code below is designed and setup in such a way that one such method (runNextTask) can exist. It is good practice to make the "critical section" in concurrent code as simple and explicit as possible (which, in turn, generally leads to an efficient "critical section").
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class SerialTaskQueue {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
// all operations on this list must be synchronized on the list itself.
SerialTaskQueue tq = new SerialTaskQueue(executor);
try {
// test running the tasks one by one
tq.add(new SleepSome(10L));
Thread.sleep(5L);
tq.add(new SleepSome(20L));
tq.add(new SleepSome(30L));
Thread.sleep(100L);
System.out.println("Queue size: " + tq.size()); // should be empty
tq.add(new SleepSome(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 List<Runnable> tasks = new LinkedList<Runnable>();
// atomic boolean used to ensure only 1 task is executed at any given time
private final AtomicBoolean executeNextTask = new AtomicBoolean(true);
private final Executor executor;
public SerialTaskQueue(Executor executor) {
this.executor = executor;
}
public void add(Runnable task) {
synchronized(tasks) { tasks.add(task); }
runNextTask();
}
private void runNextTask() {
// critical section that ensures one task is executed.
synchronized(tasks) {
if (!tasks.isEmpty()
&& executeNextTask.compareAndSet(true, false)) {
executor.execute(wrapTask(tasks.remove(0)));
}
}
}
private CallbackTask wrapTask(Runnable task) {
return new CallbackTask(task, new Runnable() {
#Override public void run() {
if (!executeNextTask.compareAndSet(false, true)) {
System.out.println("ERROR: programming error, the callback should always run in execute state.");
}
runNextTask();
}
});
}
public int size() {
synchronized(tasks) { return tasks.size(); }
}
public Runnable get(int index) {
synchronized(tasks) { return tasks.get(index); }
}
public Runnable remove(int index) {
synchronized(tasks) { return tasks.remove(index); }
}
// 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 long sleepTimeMs;
public SleepSome(long sleepTimeMs) {
this.sleepTimeMs = sleepTimeMs;
}
#Override public void run() {
try {
System.out.println(tdelta() + "Sleeping for " + sleepTimeMs + " ms.");
Thread.sleep(sleepTimeMs);
System.out.println(tdelta() + "Slept for " + sleepTimeMs + " ms.");
} catch (Exception e) {
e.printStackTrace();
}
}
private String tdelta() { return String.format("% 4d ", (System.currentTimeMillis() - startTime)); }
}
}
Update: if groups of tasks need to be executed serial, have a look at the adapted implementation here.

Categories

Resources