I run a server and it has an event handler that handles a timing system
When I run 3 of them in a row, it gives this exception
Exception in thread "Thread-8" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at EventManager.run(EventManager.java:77)
at java.lang.Thread.run(Thread.java:662)
here's the method that the issue is coming from:
EventManager.getSingleton().addEvent( new Event() {
public void execute(EventContainer c) {
p.createProjectile(p.absY, p.absX, offsetY, offsetX, 1166, 43, 31, 70, p2.playerId);
c.stop(); // stops the event from running
}
}, 950); // in ms (1 second = 1000 ms)
EventManager.getSingleton().addEvent( new Event() {
public void execute(EventContainer c) {
p2.applyDAMAGE(misc.random(25));
c.stop(); // stops the event from running
}
}, 1300); // in ms (1 second = 1000 ms)
p.secondsTillNextDfsSpecial = 120;
EventManager.getSingleton().addEvent( new Event() {
public void execute(EventContainer c) {
p.secondsTillNextDfsSpecial--;
if (p.secondsTillNextDfsSpecial == 0) {
p.canPerformDfsSpecial = true;
c.stop(); // stops the event from running
}
}
}, 1000); // in ms (1 second = 1000 ms)
import java.util.ArrayList;
import java.util.List;
/**
* Manages events which will be run in the future.
* Has its own thread since some events may need to be ran faster than the cycle time
* in the main thread.
*
* #author Graham
*
*/
public class EventManager implements Runnable {
/**
* A reference to the singleton;
*/
private static EventManager singleton = null;
/**
* A list of events that are being executed.
*/
private List<EventContainer> events;
/**
* Initialise the event manager.
*/
private EventManager() {
events = new ArrayList<EventContainer>();
}
/**
* The event manager thread. So we can interrupt it and end it nicely on shutdown.
*/
private Thread thread;
/**
* Gets the event manager singleton. If there is no singleton, the singleton is created.
* #return The event manager singleton.
*/
public static EventManager getSingleton() {
if(singleton == null) {
singleton = new EventManager();
singleton.thread = new Thread(singleton);
singleton.thread.start();
}
return singleton;
}
/**
* Initialises the event manager (if it needs to be).
*/
public static void initialise() {
getSingleton();
}
/**
* The waitFor variable is multiplied by this before the call to wait() is made.
* We do this because other events may be executed after waitFor is set (and take time).
* We may need to modify this depending on event count? Some proper tests need to be done.
*/
private static final double WAIT_FOR_FACTOR = 0.5;
#Override
/**
* Processes events. Works kinda like newer versions of cron.
*/
public synchronized void run() {
long waitFor = -1;
List<EventContainer> remove = new ArrayList<EventContainer>();
while(true) {
// reset wait time
waitFor = -1;
// process all events
for(EventContainer container : events) {
if(container.isRunning()) {
if((System.currentTimeMillis() - container.getLastRun()) >= container.getTick()) {
container.execute();
}
if(container.getTick() < waitFor || waitFor == -1) {
waitFor = container.getTick();
}
} else {
// add to remove list
remove.add(container);
}
}
// remove events that have completed
for(EventContainer container : remove) {
events.remove(container);
}
remove.clear();
// no events running
try {
if(waitFor == -1) {
wait(); // wait with no timeout
} else {
// an event is running, wait for that time or until a new event is added
int decimalWaitFor = (int)(Math.ceil(waitFor*WAIT_FOR_FACTOR));
wait(decimalWaitFor);
}
} catch(InterruptedException e) {
break; // stop running
}
}
}
/**
* Adds an event.
* #param event The event to add.
* #param tick The tick time.
*/
public synchronized void addEvent(Event event, int tick) {
events.add(new EventContainer(event,tick));
notify();
}
/**
* Shuts the event manager down.
*/
public void shutdown() {
this.thread.interrupt();
}
}</code></pre>
Ok, I see two problems:
Your events List is not synchronized and you are accessing it from different threads (one in EventManager and second in the first piece of code with addEvent()).
In this loop:
// process all events
for(EventContainer container : events) {
...
}
you are iterating over events List and you cannot add new elements to it while iteration. I assume addEvent() is adding new elements to this list, so basically you shouldn't call it during this iteration.
Both of this problems can be solved by using CopyOnWriteArrayList which enables safe access by concurrent threads and safely adding new elements during iteration (however new elements will be "visible" only in next iteration).
Solution:
private EventManager() {
events = new CopyOnWriteArrayList() ;
}
Related
I originally saw this issue with a more complex subclass of ThreadPoolExecutor, but I have simplified so now contains not much more than some additional debugging, and still get the same problem.
import com.jthink.songkong.cmdline.SongKong;
import com.jthink.songkong.ui.MainWindow;
import com.jthink.songkong.util.SongKongThreadFactory;
import java.util.concurrent.*;
import java.util.logging.Level;
public class TimeoutThreadPoolExecutor extends ThreadPoolExecutor
{
/**
* Uses the default CallerRunsPolicy when queue is full
* #param workerSize
* #param threadFactory
* #param queue
*/
public TimeoutThreadPoolExecutor(int workerSize, ThreadFactory threadFactory, LinkedBlockingQueue<Runnable> queue)
{
super(workerSize, workerSize, 0L, TimeUnit.MILLISECONDS, queue, threadFactory, new CallerRunsPolicy());
}
/**
* Allow caller to specify the RejectedExecutionPolicy
* #param workerSize
* #param threadFactory
* #param queue
* #param reh
*/
public TimeoutThreadPoolExecutor(int workerSize, ThreadFactory threadFactory, LinkedBlockingQueue<Runnable> queue, RejectedExecutionHandler reh)
{
super(workerSize, workerSize, 0L, TimeUnit.MILLISECONDS, queue, threadFactory, reh);
}
#Override
public <T> FutureCallable<T> newTaskFor(Callable<T> callable) {
return new FutureCallable<T>(callable);
}
/**
* Check not been paused
*
* #param t
* #param r
*/
#Override
protected void beforeExecute(Thread t, Runnable r) {
SongKong.checkIn();
}
/**
* After execution
*
* #param r
* #param t
*/
#Override
protected void afterExecute(Runnable r, Throwable t)
{
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>)
{
try
{
Object result = ((Future<?>) r).get();
}
catch (CancellationException ce)
{
t = ce;
}
catch (ExecutionException ee)
{
t = ee.getCause();
}
catch (InterruptedException ie)
{
Thread.currentThread().interrupt(); // ignore/reset
}
}
if (t != null)
{
MainWindow.logger.log(Level.SEVERE, "AFTER EXECUTE---" + t.getMessage(), t);
}
}
#Override
protected void terminated()
{
//All tasks have completed either naturally or via being cancelled by timeout task so close the timeout task
MainWindow.logger.severe("---Terminated:"+((SongKongThreadFactory)getThreadFactory()).getName());
MainWindow.userInfoLogger.severe("---Terminated:"+((SongKongThreadFactory)getThreadFactory()).getName());
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for(StackTraceElement ste:stackTrace)
{
MainWindow.logger.log(Level.SEVERE, ste.toString());
}
for(StackTraceElement ste:stackTrace)
{
MainWindow.userInfoLogger.log(Level.SEVERE, ste.toString());
}
}
#Override
public void shutdown()
{
MainWindow.logger.severe("---Shutdown:"+((SongKongThreadFactory)getThreadFactory()).getName());
MainWindow.userInfoLogger.severe("---Shutdown:"+((SongKongThreadFactory)getThreadFactory()).getName());
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for(StackTraceElement ste:stackTrace)
{
MainWindow.logger.log(Level.SEVERE, ste.toString());
}
for(StackTraceElement ste:stackTrace)
{
MainWindow.userInfoLogger.log(Level.SEVERE, ste.toString());
}
super.shutdown();
}
}
This ExecutorService is being used by the following class, that allow instance to asynchronously submit tasks, the ExecutorService should not be shutdown until all submitted tasks have completed.
package com.jthink.songkong.analyse.analyser;
import com.jthink.songkong.preferences.GeneralPreferences;
import com.jthink.songkong.ui.MainWindow;
import com.jthink.songkong.util.SongKongThreadFactory;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
/**
* Sets a timeout of each task submitted and cancel them if take longer than the timeout
*
* The timeout is set to 30 minutes, we only want to call if really broken, it should not happen under usual circumstances
*/
public class MainAnalyserService extends AnalyserService
{
//For monitoring/controlling when finished
private final AtomicInteger pendingItems = new AtomicInteger(0);
private final CountDownLatch latch = new CountDownLatch(1);
//If task has not completed 30 minutes after it started (added to queue) then it should be cancelled
private static final int TIMEOUT_PER_TASK = 30;
private static MainAnalyserService mas;
public static MainAnalyserService getInstanceOf()
{
return mas;
}
public static MainAnalyserService create(String threadGroup)
{
mas = new MainAnalyserService(threadGroup);
return mas;
}
public MainAnalyserService(String threadGroup)
{
super(threadGroup);
initExecutorService();
}
/**
Configure thread to match cpus but even if single cpu ensure have at least two threads to protect against
scenario where there is only cpu and that thread is waiting on i/o rather than being cpu bound this would allow
other thread to do something.
*/
#Override
protected void initExecutorService()
{
int workerSize = GeneralPreferences.getInstance().getWorkers();
if(workerSize==0)
{
workerSize = Runtime.getRuntime().availableProcessors();
}
//Even if only have single cpu we still have multithread so we dont just have single thread waiting on I/O
if(workerSize< MIN_NUMBER_OF_WORKER_THREADS)
{
workerSize = MIN_NUMBER_OF_WORKER_THREADS;
}
MainWindow.userInfoLogger.severe("Workers Configuration:"+ workerSize);
MainWindow.logger.severe("Workers Configuration:"+ workerSize);
executorService = new TimeoutThreadPoolExecutor(workerSize,
new SongKongThreadFactory(threadGroup),
new LinkedBlockingQueue<Runnable>(BOUNDED_QUEUE_SIZE),
TIMEOUT_PER_TASK,
TimeUnit.MINUTES,
new EnsureIncreaseCountIfRunOnCallingThread());
}
public AtomicInteger getPendingItems()
{
return pendingItems;
}
/**
* If queue is full this gets called and we log that we run task on local calling thread.
*/
class EnsureIncreaseCountIfRunOnCallingThread implements RejectedExecutionHandler
{
/**
* Creates a {#code CallerRunsPolicy}.
*/
public EnsureIncreaseCountIfRunOnCallingThread() { }
/**
* Executes task on calling thread, ensuring we increment count
*
* #param r the runnable task requested to be executed
* #param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown())
{
try
{
MainWindow.userInfoLogger.severe(">>SubmittedLocally:" + ((FutureCallable) r).getCallable().getClass().getName() + ":" + pendingItems.get());
r.run();
MainWindow.userInfoLogger.severe(">>CompletedLocally:" + ((FutureCallable) r).getCallable().getClass().getName() + ":" + pendingItems.get());
}
catch(Exception ex)
{
MainWindow.userInfoLogger.log(Level.SEVERE, ex.getMessage(), ex);
}
}
}
}
/**
* Increase count and then Submit to ExecutorService
*
* #param callingTask
* #param task
*/
public void submit(Callable<Boolean> callingTask, Callable<Boolean> task) //throws Exception
{
//Ensure we increment before calling submit in case rejectionExecution comes into play
int remainingItems = pendingItems.incrementAndGet();
executorService.submit(task);
MainWindow.userInfoLogger.severe(">>Submitted:" + task.getClass().getName() + ":" + remainingItems);
}
public ExecutorService getExecutorService()
{
return executorService;
}
/**
* Must be called by Callable when it has finished work (or if error)
*
* #param task
*/
public void workDone(Callable task)
{
int remainingItems = pendingItems.decrementAndGet();
MainWindow.userInfoLogger.severe(">>WorkDone:" + task.getClass().getName() + ":" +remainingItems);
if (remainingItems == 0)
{
MainWindow.userInfoLogger.severe(">Closing Latch:");
latch.countDown();
}
}
/**
* Wait for latch to close, this should occur once all submitted aysync tasks have finished in some way
*
* #throws InterruptedException
*/
public void awaitCompletion() throws InterruptedException{
latch.await();
}
}
The calling Class has
//Just waits for all the async tasks on the list to complete/fail
analyserService.awaitCompletion();
MainWindow.userInfoLogger.severe(">MainAnalyser Completed");
For one customer the terminated() method was getting called even though there are still task that have not completed, and the executorservice has only been running for 8 minutes, and no tasks have timed out. I have also seen the problem locally
Debugging shows
UserLog
05/07/2019 11.29.38:EDT:SEVERE: ----G14922:The Civil War:8907617:American Songs of Revolutionary Times and the Civil War Era:NoScore
05/07/2019 11.29.38:EDT:SEVERE: >>Submitted:com.jthink.songkong.analyse.analyser.SongSaver:69
05/07/2019 11.29.38:EDT:SEVERE: >>WorkDone:com.jthink.songkong.analyse.analyser.DiscogsSongGroupMatcher:68
05/07/2019 11.29.38:EDT:SEVERE: >MainAnalyser Finished
05/07/2019 11.29.38:EDT:INFO: Stop
DebugLog
05/07/2019 11.29.38:EDT:TimeoutThreadPoolExecutor:terminated:SEVERE: ---Terminated:Worker
So we can see there are still 68 tasks to complete, and MainAnalyser has not closed the latch, yet threadpool executor has terminated
I overridden shutdown() to see if that is called and it is not,
terminate() is being called by runWorker(), runWorker() should continue in loop until queue is empty which it is not, but something seems to cause it to leave loop and the processWorkerExit() after doing some more checks eventually terminates the whole Executor (not just a worker thread)
10/07/2019 07.11.51:BST:MainAnalyserService:submit:SEVERE: >>Submitted:com.jthink.songkong.analyse.analyser.DiscogsSongGroupMatcher:809
10/07/2019 07.11.51:BST:MainAnalyserService:workDone:SEVERE: >>WorkDone:com.jthink.songkong.analyse.analyser.MusicBrainzSongGroupMatcher2:808
10/07/2019 07.11.51:BST:TimeoutThreadPoolExecutor:terminated:SEVERE: ---Terminated:Worker
10/07/2019 07.11.51:BST:TimeoutThreadPoolExecutor:terminated:SEVERE: java.base/java.lang.Thread.getStackTrace(Unknown Source)
10/07/2019 07.11.51:BST:TimeoutThreadPoolExecutor:terminated:SEVERE: com.jthink.songkong.analyse.analyser.TimeoutThreadPoolExecutor.terminated(TimeoutThreadPoolExecutor.java:118)
10/07/2019 07.11.51:BST:TimeoutThreadPoolExecutor:terminated:SEVERE: java.base/java.util.concurrent.ThreadPoolExecutor.tryTerminate(Unknown Source)
10/07/2019 07.11.51:BST:TimeoutThreadPoolExecutor:terminated:SEVERE: java.base/java.util.concurrent.ThreadPoolExecutor.processWorkerExit(Unknown Source)
10/07/2019 07.11.51:BST:TimeoutThreadPoolExecutor:terminated:SEVERE: java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
10/07/2019 07.11.51:BST:TimeoutThreadPoolExecutor:terminated:SEVERE: java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
10/07/2019 07.11.51:BST:TimeoutThreadPoolExecutor:terminated:SEVERE: java.base/java.lang.Thread.run(Unknown Source)
Because ThreadPoolExecutor is part of Standard Java I cannot (easily) set breakpoints to try and find out what it is doing, this is ThreadPoolExecutor code (standard Jave not my code)
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
We experimented with the queue size in the Executor, by default it was 100 because I did not want it to get too large as the queue tasks will use more memory and I would rather the calling tasks just runs itself if queue is busy. But in an attempt solve the issue (and remove need for CallerRunPolicy to be called because queue full) I increased queue size to 1000 and this caused the error to occur more quickly and then removed the limit completely and continue to fail more rapidly
new LinkedBlockingQueue<Runnable>(BOUNDED_QUEUE_SIZE),
I was looking at an alternative to ThreadExecutorPool and came across ForkJoinPool - https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ForkJoinPool.html
One thing I noticed is that ForkJoinPool has different methods for submitting tasks from within a task submitted to ForkJoinPool compared to submitting form outside. I dont why this is, but wondering if because I am submitting tasks from within tasks being run by Executor whther this could cause issue in some way ?
I have now managed to create own version of ThreadPoolExecutor by simply copying/pasting code into new Class, renaming, and also having to create a version of RejectedExcecutionhandler that expects my class rather than ThreadPoolExecutor and got this running.
Started to add some debugging to see if I can decipher what is going on, any ideas ?
Befotre call to processWorkerExit I added
MainWindow.userInfoLogger.severe("-----------------------"+getTaskCount()
+":"+getActiveCount()
+":"+w.completedTasks
+":"+ completedAbruptly);
and got on failure
-----------------------3686:0:593:false
For a long time I thought the problem must be with my code, I then started thinking the issue was with ThreadPoolExecutor, but adding debugging to my own version of runWorker() showed the problem was indeed my own code.
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
MainWindow.userInfoLogger.severe("-----------------------"+workQueue.size());
From this I could see that whilst the worker queue was getting generally longer and matched the value of
MainThreadAnalyzer.pendingItems -noOfWorkerThreads
at a particular point the two values diverged, and this was when the SongLoader process (which mistakenly I had not really considered) finished. So MainThreadAnalyzer was continuing to submit work increasing the value of pendingItems , but the work queue size of the Executor was getting smaller.
This lead to realization that the Executor had shutdown() alot earlier, but we hadn't realized this because only check latch after songloader had closed.
And the reason it had shutdown was because early on the MainAnalyzerThread was completing the work more quickly then SongLoader was submitting it so the value of pendingItems was temporarily set to zero allowing the latch to be closed.
The solution is as follows
Add a boolean flag to indicate when songLoader has completed and only allow latch to be closed once this flag is set.
private boolean songLoaderCompleted = false;
public void workDone(Callable task)
{
int remainingItems = pendingItems.decrementAndGet();
MainWindow.logger.severe(">>WorkDone:" + task.getClass().getName() + ":" +remainingItems);
if (remainingItems == 0 && songLoaderCompleted)
{
MainWindow.logger.severe(">Closing Latch:");
latch.countDown();
}
}
Then in main thread set this flag once SongLoader has completed
//Start SongLoader
ExecutorService songLoaderService = SongLoader.getExecutorService();
songLoaderService.submit(loader);
//SongLoader uses CompletionService when calls LoadFolderWorkers so shutdown wont return until all folder
//submissions completed to the MainAnalyserService
songLoaderService.shutdown();
songLoaderService.awaitTermination(10, TimeUnit.DAYS);
MainWindow.userInfoLogger.severe(">Song Loader Finished");
//Were now allowed to consider closing the latch because we know all songs have now been loaded
//so no false chance of zeroes
analyserService.setSongLoaderCompleted();
//Just waits for all the async tasks on the list to complete/fail
analyserService.awaitCompletion();
MainWindow.userInfoLogger.severe(">MainAnalyser Completed");
//This should be immediate as there should be no tasks still remaining
analyserService.getExecutorService().shutdown();
analyserService.getExecutorService().awaitTermination(10, TimeUnit.DAYS);
You are just misusing ExecutorService.
What you are doing (even in your "solution") is this
Submit tasks
Wait for them to finish
Shutdown
Wait again for shutdown to happen (why is that actually?)
What you should do is:
Submit tasks
Shutdown the executor to not allow any new tasks
Await termination - this will block until all tasks are finished, or timeout is reached
You should check for return status of awaitTermination because
If true - all tasks are finished before given timeout
If false - not all tasks are finished yet - and probably you should not start your second pool in such case.
Also there are 2 options how to use thread executor. You can spawn worker threads and let them decide what they supposed to do - like you did by looping in worker thread for new tasks
Or (which I prefer), wrap whatever is your job supposed to do into separate task (most probably what you have in loop body) and submit as separate task to pool. ExecutorService will do the scheduling for you.
Let's say we have a thread-pool with a limited number of threads.
Executor executor = Executors.newFixedThreadPool(3);
Now let's say one of the active tasks must sleep for 3 seconds (for whatever reason).
executor.execute(() -> {
try {
Thread.sleep(3000L);
} catch (InterruptedException ignore) {}
});
How can we implement such a thread-pool in way that, when a task sleeps (or waits on a monitor/condition), the thread1 can be used effectively to run another task?
1 By thread I do not mean the "physical" Java thread, because that would be impossible while the thread is asleep. What I mean is, the thread-pool to have an abstract implementation which virtually seems to allow a thread to run another task during sleeping. The key point is that there are always N simultaneously running (non-sleeping) tasks.
Somewhat similar to the way a monitor handles access to a critical region:
If a thread waits on a resource, the resource can be used by another thread.
If the thread is notified, it is placed into the waiting set to (re-)gain access to that resource.
What you are asking for is essentially implementing coroutines/fibers on top of JVM/OS thread. Nice talk was given by Sanhong Li about the way how Alibaba's engineers implemented such construction - the idea is instead of relying on OS thread scheduler you need to rely on your own Selector.
See also Loom project for fibers (user-land green threads).
I implemented a minimal working example which basically does what I think you want.
A Task interface (much like the runnable interface, just with a passed Context to perform waiting)
package io.medev.stackoverflow;
import java.util.concurrent.TimeUnit;
import java.util.function.BooleanSupplier;
public interface Task {
/**
* Wraps the given runnable into a Task with a not guessable execution time (meaning guessExecutionTime always returns Long.MAX_VALUE)
* #param runnable The runnable to wrap
* #return a Task wrapping this runnable
*/
static Task wrap(Runnable runnable) {
return wrap(runnable, Long.MAX_VALUE);
}
/**
* Wraps the given runnable using the given guessedExecutionTimeMillis
* #param runnable The runnable to wrap
* #param guessedExecutionTimeMillis The guessed execution time in millis for this runnable
* #return a Task wrapping this runnable
*/
static Task wrap(Runnable runnable, long guessedExecutionTimeMillis) {
return new Task() {
#Override
public long guessExecutionTimeMillis() {
return guessedExecutionTimeMillis;
}
#Override
public void run(Context context) {
runnable.run();
}
};
}
/**
* Should more or less guess how long this task will run
* #return The execution time of this Task in milliseconds
*/
long guessExecutionTimeMillis();
void run(Context context);
interface Context {
/**
* Block until the condition is met, giving other Tasks time to execute
* #param condition the condition to check
* #throws InterruptedException if the current thread is interrupted
*/
void idle(BooleanSupplier condition) throws InterruptedException;
/**
* Blocks at least for the given duration, giving other Tasks time to execute
* #param timeout
* #param timeUnit
* #throws InterruptedException if the current thread is interrupted
*/
void idle(long timeout, TimeUnit timeUnit) throws InterruptedException;
/**
* Blocks until the condition is met or the timeout expires, giving other Tasks time to execute
* #param condition the condition to check
* #param timeout
* #param timeUnit
* #throws InterruptedException if the current thread is interrupted
*/
void idle(BooleanSupplier condition, long timeout, TimeUnit timeUnit) throws InterruptedException;
}
}
And a basic fixed thread-pool Executor - but you have to depend on the concrete implementation here:
package io.medev.stackoverflow;
import java.util.Comparator;
import java.util.concurrent.*;
import java.util.function.BooleanSupplier;
public class TimeEfficientExecutor implements Executor {
private final BlockingQueue<Task> taskQueue;
private final CountDownLatch latch;
private volatile boolean alive;
public TimeEfficientExecutor(int threads) {
this.taskQueue = new PriorityBlockingQueue<>(10, Comparator.comparingLong(Task::guessExecutionTimeMillis));
this.latch = new CountDownLatch(threads);
this.alive = true;
for (int i = 0; i < threads; i++) {
Thread thread = new Thread(new TimeEfficientExecutorRunnable());
thread.start();
}
}
#Override
public void execute(Runnable runnable) {
execute(Task.wrap(runnable));
}
public void execute(Runnable runnable, long guessedExecutionTimeMillis) {
execute(Task.wrap(runnable, guessedExecutionTimeMillis));
}
public void execute(Task task) {
this.taskQueue.offer(task);
}
public void shutdown() {
this.alive = false;
}
public void awaitShutdown() throws InterruptedException {
this.latch.await();
}
public void awaitShutdown(long timeout, TimeUnit timeUnit) throws InterruptedException {
this.latch.await(timeout, timeUnit);
}
private class TimeEfficientExecutorRunnable implements Runnable {
#Override
public void run() {
try {
while (TimeEfficientExecutor.this.alive) {
Task task = TimeEfficientExecutor.this.taskQueue.poll();
if (task != null) {
try {
task.run(new IdleTaskContext());
} catch (Exception e) {
// TODO: logging
}
}
}
} finally {
TimeEfficientExecutor.this.latch.countDown();
}
}
}
private class IdleTaskContext implements Task.Context {
#Override
public void idle(BooleanSupplier condition) throws InterruptedException {
idle(condition, Long.MAX_VALUE);
}
#Override
public void idle(long timeout, TimeUnit timeUnit) throws InterruptedException {
idle(() -> false, timeout, timeUnit);
}
#Override
public void idle(BooleanSupplier condition, long timeout, TimeUnit timeUnit) throws InterruptedException {
idle(condition, System.currentTimeMillis() + timeUnit.toMillis(timeout));
}
private void idle(BooleanSupplier condition, long idleUntilTs) throws InterruptedException {
long leftMillis = idleUntilTs - System.currentTimeMillis();
while (TimeEfficientExecutor.this.alive && !condition.getAsBoolean() && leftMillis >= 1L) {
Task task = TimeEfficientExecutor.this.taskQueue.poll(leftMillis, TimeUnit.MILLISECONDS);
leftMillis = idleUntilTs - System.currentTimeMillis();
if (task != null) {
if (leftMillis >= 1L && task.guessExecutionTimeMillis() < leftMillis) {
task.run(new IdleTaskContext());
} else {
TimeEfficientExecutor.this.taskQueue.offer(task);
}
}
}
}
}
}
Note that you can't just step down the stack - and the stack is bound to the executing thread. That means that it is not possible to jump back into an underlying idleing task if some "Sub"-Task starts idleing. You have to "trust" what each task returns in the guessExecutionTimeMillis-Method.
Thanks to the PriorityQueue used in the Executor, the queue will always return the task with the lowest exeuction time.
I am trying to create the following concept: start a thread whenever a specific screen gets launched. The thread should receive a message which is called a "tag", which is not working yet so I got it hardcoded.
Then show an AnchorPane based on the validation of the tag: either the showError or showValid function. However, the application first runs the function and then shows the AnchorPane and the updated ListView.
I want to start the following thread whenever a specific screen launches.
public class RFIDThread extends Thread{
private static final Logger logger = Logger.getLogger(RFIDApplication.class);
/**
* The incoming data stream from the LLRP reader connection
*/
private DataInputStream inStream = null;
/**
* The socket for the connection to the LLRP Reader
*/
private Socket socket = null;
/**
* A queue to store incoming LLRP Messages
*/
private LinkedBlockingQueue<LLRPMessage> queue = null;
private String[] found_tags = new String[5];
private JSONArray valid_tags;
private TagsListController controller;
/**
* Thread for constant reading of the stream
*
* #param socket
* #param controller
* #param tags
* #param orderNumber
* #throws java.io.IOException
*/
public RFIDThread(Socket socket, TagsListController controller, JSONArray tags, String orderNumber) throws IOException {
this.socket = socket;
this.controller = controller;
this.queue = new LinkedBlockingQueue<LLRPMessage>();
try {
this.inStream = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
logger.error("Cannot get input stream", e);
}
valid_tags = tags;
found_tags[0] = "aga9jrjahr";
found_tags[1] = "agahs4suj";
found_tags[2] = "a79gtvaTGBQG";
found_tags[3] = "at3anit08av9agq4";
//found_tags[4] = "4a05355d0000000000017cc0";
//start();
}
#Override
public void run()
{
super.run();
if (socket.isConnected()) {
for (String found_tag : found_tags) {
Integer index = valid_tags.indexOf(found_tag);
if (index > 0) {
Platform.runLater(() -> {
controller.showValid(found_tag);
});
} else {
Platform.runLater(() -> {
controller.showError(found_tag);
});
}
}
}
}
}
The thread should run functions: showError or showValid based on the tag it receives. Currently I have some hardcoded tags set-up which are all invalid so it should run the showError() function. This function: adds the tag to a ListView, sets the tag as text of a label, display the AnchorPane, sleep 1 second, hide the AnchorPane and then sleep 1 second. After this, the next tag must be processed.
/**
* Display red screen
* #param tag
*/
public void showError(String tag) {
this.found_tags_list.getItems().add(tag);
this.errorTag.setText(tag);
System.out.println(errorTag.getText());
this.errorPane.setVisible(true);
pause(1000);
this.validPane.setVisible(false);
pause(1000);
}
You didn't post the code for your pause() method, so I'm going to assume it does something like Thread.sleep(...) and handles the interrupted exception appropriately. I.e. I'm going to assume you have something like:
public void pause(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
}
}
The showError() method is being (explicitly) executed on the FX Application Thread. That thread is also responsible for rendering the UI. Consequently, the UI can't be redrawn while the showError() method is executing (because a single thread can't do two things at once: that's basically the definition of "thread").
So it's always an error to block the FX Application Thread, because it makes the UI unresponsive and prevents it from being drawn.
If you are already on the FX Application Thread, and want to schedule some code to execute in the future, you can do that with a PauseTransition. So instead of
this.errorPane.setVisible(true);
pause(1000);
this.validPane.setVisible(false);
you can do
this.errorPane.setVisible(true);
PauseTransition pause = new PauseTransition(Duration.millis(1000));
pause.setOnFinished(e -> this.validPane.setVisible(false));
pause.play();
The second pause in that method makes less sense. It simply pauses the FX Application Thread, and then the method exits, so there is nothing it is waiting for anyway.
If the idea is to make the background thread pause at that point, you should call pause() on the background thread. (Calling it on the FX Application Thread, obviously, won't make the background thread pause anyway.)
So I think your code should look like:
public class RFIDThread extends Thread {
// ...
#Override
public void run() {
super.run();
if (socket.isConnected()) {
for (String found_tag : found_tags) {
Integer index = valid_tags.indexOf(found_tag);
if (index > 0) {
Platform.runLater(() -> controller.showValid(found_tag));
} else {
Platform.runLater(() -> controller.showError(found_tag));
}
pause(2000);
}
}
}
}
Note that I'm guessing here the intention is for your background thread to pause for (approximately) one second after the pane you show is hidden again, which would mean it needs to pause for two seconds in total.
In the controller, you do
public void showError(String tag) {
this.found_tags_list.getItems().add(tag);
this.errorTag.setText(tag);
System.out.println(errorTag.getText());
this.errorPane.setVisible(true);
PauseTransition pause = new PauseTransition(Duration.millis(1000));
pause.setOnFinished(e -> this.validPane.setVisible(false));
pause.play();
}
I'm requested in an assignment to implement pingpong game that called "ping" and "pong" correctly (meaning, no pong before ping) 10 times. Meaning, the final output in the console should be: "ping!(1)", "pong!(1)", "ping!(2)", "pong!(2)" etc.
The demand is to implement gamepingpongthread with semaphores, reetrantlock and countdown latch.
My problem is that the print order is not always as requested, and I wonder what I'm doing wrong.
Here's the code:
// Import the necessary Java synchronization and scheduling classes.
import java.util.concurrent.Semaphore;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
/**
* #class PingPongRight
*
* #brief This class implements a Java program that creates two
* instances of the PlayPingPongThread and start these thread
* instances to correctly alternate printing "Ping" and "Pong",
* respectively, on the console display.
*/
public class PingPongRight
{
/**
* #class SimpleSemaphore
*
* #brief This class provides a simple counting semaphore
* implementation using Java a ReentrantLock and a
* ConditionObject.
*/
static public class SimpleSemaphore
{
private int mPermits;
private ReentrantLock lock = new ReentrantLock();
private Condition isZero = lock.newCondition();
/**
* Constructor initialize the data members.
*/
public SimpleSemaphore (int maxPermits)
{
mPermits = maxPermits;
}
/**
* Acquire one permit from the semaphore.
*/
public void acquire() throws InterruptedException
{
lock.lock();
while (mPermits == 0)
isZero.await();
mPermits--;
lock.unlock();
}
/**
* Return one permit to the semaphore.
*/
void release() throws InterruptedException
{
lock.lock();
try {
mPermits++;
isZero.signal();
} finally {
lock.unlock();
}
}
}
/**
* Number of iterations to run the test program.
*/
public static int mMaxIterations = 10;
/**
* Latch that will be decremented each time a thread exits.
*/
public static CountDownLatch latch = new CountDownLatch(2);
/**
* #class PlayPingPongThread
*
* #brief This class implements the ping/pong processing algorithm
* using the SimpleSemaphore to alternate printing "ping"
* and "pong" to the console display.
*/
public static class PlayPingPongThread extends Thread
{
private String message;
private SimpleSemaphore semaphore;
/**
* Constructor initializes the data member.
*/
public PlayPingPongThread (String msg, SimpleSemaphore pingOrPong)
{
message = msg;
semaphore = pingOrPong;
}
/**
* Main event loop that runs in a separate thread of control
* and performs the ping/pong algorithm using the
* SimpleSemaphores.
*/
public void run ()
{
for (int i = 1 ; i <= mMaxIterations ; i++) {
try {
semaphore.acquire();
System.out.println(message + "(" + i + ")");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
latch.countDown();
}
}
/**
* The main() entry point method into PingPongRight program.
*/
public static void main(String[] args) {
try {
// Create the ping and pong SimpleSemaphores that control
// alternation between threads.
SimpleSemaphore pingSemaphore = new SimpleSemaphore(mMaxIterations);
SimpleSemaphore pongSemaphore = new SimpleSemaphore(mMaxIterations);
System.out.println("Ready...Set...Go!");
// Create the ping and pong threads, passing in the string
// to print and the appropriate SimpleSemaphores.
PlayPingPongThread ping = new PlayPingPongThread("Ping!", pingSemaphore);
PlayPingPongThread pong = new PlayPingPongThread("Pong!", pongSemaphore);
// Initiate the ping and pong threads, which will call the run() hook method.
ping.start();
pong.start();
// Use barrier synchronization to wait for both threads to finish.
latch.await();
}
catch (java.lang.InterruptedException e)
{}
System.out.println("Done!");
}
}
Thanks in advance
My problem is that the print order is not always as requested, and I wonder what I'm doing wrong.
I think your problem is that both the ping and pong threads are acquiring and releasing their own semaphore. I think you need to pass both semaphores to both threads. Each thread calls acquire() on the acquireSemaphore and release() on the releaseSemaphore.
acquireSemaphore.acquire();
System.out.println(message + "(" + i + ")");
releaseSemaphore.release();
The thread would look like:
public PlayPingPongThread (String msg, SimpleSemaphore acquireSemaphore,
SimpleSemaphore releaseSemaphore)
Then the threads are initialized as:
// ping acquires on the ping, releases the pong
PlayPingPongThread ping = new PlayPingPongThread("Ping!", pingSemaphore, pongSemaphore);
// pong acquires on the pong, releases the ping
PlayPingPongThread pong = new PlayPingPongThread("Pong!", pongSemaphore, pingSemaphore);
The pingSemaphore should start with 1 permit and the pong one should start with 0.
ping first calls acquire() on the pingSemaphore and it is given.
ping prints out ping.
ping calls release() on the pongSemaphore.
This wakes up pong (assuming your semaphore code works of course).
pong prints pong.
pong calls release() on the pingSemaphore.
repeat...
You can also use the Reentrant lock condition to implement ping pong game, which is very similar to wait-notify.
package com.example.thread;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class PingPongUsingReentrantCondition {
private static ReentrantLock lock = new ReentrantLock(true);
private Condition conditionMet = lock.newCondition();
public static void main(String[] args) {
PingPongUsingReentrantCondition pingPong = new PingPongUsingReentrantCondition();
int times = 10;
Thread t1 = new Thread(() -> pingPong.pingpong("Ping!", times));
Thread t2 = new Thread(() -> pingPong.pingpong("Pong!", times));
t1.start();
t2.start();
}
public void pingpong(String s, int times) {
int counter = 1;
while(counter<=times) {
run(s, counter);
counter = counter+1;
}
}
public void run(String s, int counter) {
lock.lock();
try {
conditionMet.await(2, TimeUnit.SECONDS);
System.out.println(s + "(" + counter + ")");
conditionMet.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
I am supposed to process images in a multithreaded mode using Java. I may having varying number of images where as my number of threads are fixed. I have to process all the images using the fixed set of threads.
I am just stuck up on how to do it, I had a look ThreadExecutor and BlockingQueues etc...I am still not clear. What I am doing is,
- Get the images and add them in a LinkedBlockingQueue which has runnable code of the image processor.
- Create a threadpoolexecutor for which one of the arguements is the LinkedBlockingQueue earlier.
- Iterate through a for loop till the queue size and do a threadpoolexecutor.execute(linkedblockingqueue.poll).
- all i see is it processes only 100 images which is the minimum thread size passed in LinkedBlockingQueue size.
I see I am seriously wrong in my understanding somewhere, how do I process all the images in sets of 100(threads) until they are all done? Any examples or psuedocodes would be highly helpful
Thanks!
J
Here is a sample class that I wrote. The whole thing runs standalone and prints a number from 1 to 100 each from a ThreadPool. Pretty much all you need to do is update the Request class to pass in what you want and to re-implement ImageProcessor.
package com.rch.test;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class Executor
{
/**
* Class to encapsulate a request
*
* #author romain
*/
static class Request
{
String someText;
Request(String someText)
{
this.someText = someText;
}
public String getSomeText()
{
return someText;
}
}
/**
* Creates a Thread that listens on a queue to process messages
*
* #author romain
*/
static class ServerThread implements Runnable
{
private BlockingQueue<Request> queue = new LinkedBlockingQueue<Request>();
boolean stop = false;
/**
* Does all the work
*/
#Override
public void run()
{
ExecutorService pool = Executors.newFixedThreadPool(3);
try
{
while (!stop)
{
Request req = queue.poll(1000L, TimeUnit.MILLISECONDS);
if (req != null)
{
Runnable runnable = new Executor.ImageProcessor(req);
pool.execute(runnable);
}
}
}
catch (InterruptedException ie)
{
System.out.println("Log something here");
}
finally
{
pool.shutdown();
}
}
/**
* Accepts a message on the queue
* #param request
*/
public void accept(Request request)
{
queue.add(request);
}
public void stopProcessing()
{
stop = true;
}
}
/**
* class to do the actual work
* #author romain
*/
static class ImageProcessor implements Runnable
{
String someText;
ImageProcessor(Request req)
{
this.someText = req.getSomeText();
}
#Override
public void run()
{
System.out.println(someText);
// Process Image here
}
}
/**
* Test Harness
* #param args
*/
public static void main(String[] args)
{
// Initialize
ServerThread processor = new ServerThread();
Thread aThread = new Thread(processor);
aThread.start();
// Wait for Thread to start
try
{
Thread.sleep(500L);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
for (int i = 0; i < 100; i++)
{
String text = "" + i;
Request aRequest = new Request(text);
processor.accept(aRequest);
}
// Give it enough time to finish
try
{
Thread.sleep(500L);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
// Tell the thread to finish processing
processor.stopProcessing();
// Wait for the Thread to complete
try
{
aThread.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
You can think of each processing operation being a 'task'. Place these tasks in a single queue, and have each thread consuming a task from this thread each time they complete a task.
Sun's tutorials is really good so i will just post the link Defining and Starting a Thread
Quote:
Threads are sometimes called lightweight processes. Both processes and threads provide an execution environment, but creating a new thread requires fewer resources than creating a new process.
Threads exist within a process — every process has at least one. Threads share the process's resources, including memory and open files. This makes for efficient, but potentially problematic, communication.
while(que is not empty)
start new set of image-processing-thread