I have a bunch of threads that spawn somewhat arbitrarily. When they are racing each other, only the one that spawned last is relevant. The other threads can be thrown away or stopped. But I am not sure how to do that, so I have implemented a very basic counter that checks whether the thread is the latest spawned thread.
edit: I would like to be able to kill threads that are taking too long (as they are no longer necessary); probably not from within the threads themselves as they are busy doing something else.
This code works, it seems. But it doesn't feel robust. Can someone give me a hint toward a proper way to do this?
class Main {
private static volatile int latestThread = 0;
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
spawnThread();
}
}
private static void spawnThread() {
latestThread++;
int thisThread = latestThread;
new Thread(() -> {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (latestThread == thisThread) {
// only the latest "active" thread is relevant
System.out.println("I am the latest thread! " + thisThread);
}
}).start();
}
}
output:
I am the latest thread! 10
code in replit.com
ThreadPoolExecutor is almost what I need, specifically DiscardOldestPolicy. You can set the queue size to 1, so one thread is running and one thread is in the queue, and the oldest in the queue just gets shunted. Clean!
But it finishes two threads (not only the latest), which is not 100% what I was looking for. Although arguably good enough:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class DiscardOldest {
private static int threadCounter = 1;
public static void main(String[] args) throws InterruptedException {
int poolSize = 0;
int maxPoolSize = 1;
int queueSize = 1;
long aliveTime = 1000;
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(queueSize);
ThreadPoolExecutor executor = new ThreadPoolExecutor(poolSize, maxPoolSize, aliveTime, TimeUnit.MILLISECONDS, queue, new ThreadPoolExecutor.DiscardOldestPolicy());
for (int i = 0; i < 4; i++) {
spawnThread(executor);
}
}
private static void spawnThread(ThreadPoolExecutor executor) {
final int thisThread = threadCounter++;
System.out.println(thisThread + " spawning");
executor.execute(() -> {
try {
Thread.sleep(100);
System.out.println(thisThread + " finished!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
Ouput:
1 spawning
2 spawning
3 spawning
4 spawning
1 finished!
4 finished!
Rather than relaying on an index, a born time could be set. If there's a younger thread (was born later) the thread should terminate its execution.
public class Last {
private static volatile long latestThread = 0L;
/**
* #param args
*/
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
spawnThread(System.nanoTime(), i);
}
}
private static void spawnThread(long startTime, int index) {
new Thread(() -> {
latestThread = startTime;
long thisThread = startTime;
boolean die = false;
try {
while (!die) {
Thread.sleep(1);
if (thisThread < latestThread) {
System.out.println(
index + ": I am not the latest thread :-(\n\t" + thisThread + "\n\t" + latestThread);
die = true;
} else if (thisThread == latestThread) {
System.out.println(
index + ": Yes! This is the latest thread!\n\t" + thisThread + "\n\t" + latestThread);
Thread.sleep(1);
System.out.println("Bye!");
die = true;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
Result:
0: I am not the latest thread :-(
39667589567880
39667602317461
2: Yes! This is the latest thread!
39667602317461
39667602317461
1: I am not the latest thread :-(
39667602257160
39667602317461
Bye!
I did a little research based on comments from everybody (thanks!) and ThreadPoolExecutor is almost what I need, but I want a pool with the total size of 1 (no queue) that kills the active thread once a new thread comes along, which is not allowed in a thread pool and not in line with what a ThreadPool is for. So instead, I came up with a reference to the active thread, and when a new thread comes a long it kills the old one, which seems to do what I want:
import java.util.concurrent.atomic.AtomicInteger;
public class Interrupt {
private static final AtomicInteger CURRENT_THREAD = new AtomicInteger(0);
private static Thread activeThread = new Thread(() -> {});
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 4; i++) {
spawnThread();
Thread.sleep(3);
}
}
private static void spawnThread() {
if (activeThread.isAlive()) {
activeThread.interrupt();
}
activeThread = new Thread(() -> {
int thisThread = CURRENT_THREAD.incrementAndGet();
System.out.println(thisThread + " working");
try {
Thread.sleep(1000);
System.out.println(thisThread + " finished!");
} catch (InterruptedException ignored) {}
});
activeThread.start();
}
}
Output:
3 working
2 working
1 working
4 working
4 finished!
Related
im trying to understand the barrier problem. im still really new to programming but was presented with this problem in class to solve.
"I have to solve the barrier problem using counting semaphores. You can assume that there is a shared variable N which indicates the number of concurrent threads in the system. When the first N −1 threads arrive at the barrier, they should block until the Nth thread arrives, at which point all threads might proceed.
The shared counter variable can be used to keep track of the number of threads that have arrived and the semaphores mutex and barrier can be used to solve the synchronization problem."
import java.util.concurrent.Semaphore;
public class BarrierSynchronization extends Thread {
int N;
int count;
Semaphore mutex;
Semaphore barrier;
public BarrierSynchronization ()
{
this.N = 5;
this.count = 0;
this.mutex = new Semaphore(1);
this.barrier = new Semaphore(0);
}
public void run()
{
try {
mutex.acquire();
count = count + 1;
System.out.println(Thread.currentThread().getName() + ": " + count);
mutex.release();
if (count == N)
{
barrier.release();
System.out.println("All " + count + " threads have reached the barrier. The barrier is now open" );
} // unblock one thread
barrier.acquire();
barrier.release();
System.out.println(Thread.currentThread().getName() + " has passed the barrier");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
i tried to implement the pseudo code from the little book of semaphores. i called on this thread in main class and ran it but it gives an error about mutex.wait() for some reason. when i remove that bit of the code it runs but shows nothing. what exactly am i supposed to do for this problem?
public class Main {
public static void main(String[] args) throws InterruptedException
{
BarrierSynchronization barrier = new BarrierSynchronization();
Thread bs1 = new Thread(barrier);
Thread bs2 = new Thread(barrier);
Thread bs3 = new Thread(barrier);
Thread bs4 = new Thread(barrier);
Thread bs5 = new Thread(barrier);
bs1.start();
bs2.start();
bs3.start();
bs4.start();
bs5.start();
}
why does it output the rare one before the barrier is unlocked for all the threads? i think im close enough to solving this problem. is a race condition or something?
CLICK TO SEE IMAGE
Might be a bit late, but here is an implementation with a driver code that works. You have to garante mutual exclusion and keep track of the number of threads that arrive at the barrier.
public class Barrier {
private int capacity;
private Semaphore s, exclusao, counter;
public Barrier(int capacity) {
this.capacity = capacity;
counter = new Semaphore(0);
s = new Semaphore(0);
exclusao = new Semaphore(1);
}
public void espera() throws InterruptedException {
exclusao.acquire();
if (counter.availablePermits() < capacity - 1) {
counter.release();
exclusao.release();
s.acquire();
} else {
exclusao.release();
System.out.println("RELEASE ALL");
for (int i = 0; i < capacity; i++) {
s.release();
}
}
}
}
class TesteThread extends Thread {
private Barrier b;
private long waitPeriod;
public TesteThread(long wait, Barrier b) {
this.b = b;
this.waitPeriod = wait;
System.out.println("Thread started" + this.getName());
}
public void espera() throws InterruptedException {
b.espera();
}
#Override
public void run() {
try {
System.out.println("Thread a dormir " + this.getName());
sleep(waitPeriod);
System.out.println("Thread a esperar " + this.getName());
espera();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class BarrierExample {
public static void main(String[] args) throws InterruptedException {
Barrier BR = new Barrier(5);
TesteThread[] teste = new TesteThread[5];
for (int i = 0; i < teste.length; i++) {
teste[i] = new TesteThread((long) (Math.random() * 1000), BR);
teste[i].start();
}
for (int i = 0; i < teste.length; i++) {
teste[i].join();
}
}
}`package examesFSO.exame2020_normal;
import java.util.concurrent.Semaphore;
public class Barrier {
private int capacity;
private Semaphore s, exclusao, counter;
public Barrier(int capacity) {
this.capacity = capacity;
counter = new Semaphore(0);
s = new Semaphore(0);
exclusao = new Semaphore(1);
}
public void espera() throws InterruptedException {
exclusao.acquire();
if (counter.availablePermits() < capacity - 1) {
counter.release();
exclusao.release();
s.acquire();
} else {
System.out.println("RELEASE ALL");
for (int i = 0; i < capacity; i++) {
s.release();
}
}
exclusao.release();
}
}
class TesteThread extends Thread {
private Barrier b;
private long waitPeriod;
public TesteThread(long wait, Barrier b) {
this.b = b;
this.waitPeriod = wait;
System.out.println("Thread instanciada " + this.getName());
}
public void espera() throws InterruptedException {
b.espera();
}
#Override
public void run() {
try {
System.out.println("Thread a dormir " + this.getName());
sleep(waitPeriod);
System.out.println("Thread a esperar " + this.getName());
espera();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class BarrierExample {
public static void main(String[] args) throws InterruptedException {
Barrier BR = new Barrier(5);
TesteThread[] teste = new TesteThread[5];
for (int i = 0; i < teste.length; i++) {
teste[i] = new TesteThread((long) (Math.random() * 1000), BR);
teste[i].start();
}
for (int i = 0; i < teste.length; i++) {
teste[i].join();
}
}
}
I have the following work queue implementation, which I use to limit the number of threads in use. It works by me initially adding a number of Runnable objects to the queue, and when I am ready to begin, I run "begin()". At this point I do not add any more to the queue.
public class WorkQueue {
private final int nThreads;
private final PoolWorker[] threads;
private final LinkedList queue;
Integer runCounter;
boolean hasBegun;
public WorkQueue(int nThreads) {
runCounter = 0;
this.nThreads = nThreads;
queue = new LinkedList();
threads = new PoolWorker[nThreads];
hasBegun = false;
for (int i = 0; i < nThreads; i++) {
threads[i] = new PoolWorker();
threads[i].start();
}
}
public boolean isQueueEmpty() {
synchronized (queue) {
if (queue.isEmpty() && runCounter == 0) {
return true;
} else {
return false;
}
}
}
public void begin() {
hasBegun = true;
synchronized (queue) {
queue.notify();
}
}
public void add(Runnable r) {
if (!hasBegun) {
synchronized (queue) {
queue.addLast(r);
runCounter++;
}
} else {
System.out.println("has begun executing. Cannot add more jobs ");
}
}
private class PoolWorker extends Thread {
public void run() {
Runnable r;
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
queue.wait();
} catch (InterruptedException ignored) {
}
}
r = (Runnable) queue.removeFirst();
}
// If we don't catch RuntimeException,
// the pool could leak threads
try {
r.run();
synchronized (runCounter) {
runCounter--;
}
} catch (RuntimeException e) {
// You might want to log something here
}
}
}
}
}
This is a runnable I use to keep track of when all the jobs on the work queue have finished:
public class QueueWatcher implements Runnable {
private Thread t;
private String threadName;
private WorkQueue wq;
public QueueWatcher(WorkQueue wq) {
this.threadName = "QueueWatcher";
this.wq = wq;
}
#Override
public void run() {
while (true) {
if (wq.isQueueEmpty()) {
java.util.Date date = new java.util.Date();
System.out.println("Finishing and quiting at:" + date.toString());
System.exit(0);
break;
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(PlaneGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public void start() {
wq.begin();
System.out.println("Starting " + threadName);
if (t == null) {
t = new Thread(this, threadName);
t.setDaemon(false);
t.start();
}
}
}
This is how I use them:
Workqueue wq = new WorkQueue(9); //Get same results regardless of 1,2,3,8,9
QueueWatcher qw = new QueueWatcher(wq);
SomeRunnable1 sm1 = new SomeRunnable1();
SomeRunnable2 sm2 = new SomeRunnable2();
SomeRunnable3 sm3 = new SomeRunnable3();
SomeRunnable4 sm4 = new SomeRunnable4();
SomeRunnable5 sm5 = new SomeRunnable5();
wq.add(sm1);
wq.add(sm2);
wq.add(sm3);
wq.add(sm4);
wq.add(sm5);
qw.start();
But regardless of how many threads I use, the result is always the same - it always takes about 1m 10seconds to complete. This is about the same as when I just did a single threaded version (when everything ran in main()).
If I set wq to (1,2,3--9) threads it is always between 1m8s-1m10s. What is the problem ? The jobs (someRunnable) have nothing to do with each other and cannot block each other.
EDIT: Each of the runnables just read some image files from the filesystems and create new files in a separate directory. The new directory eventually contains about 400 output files.
EDIT: It seems that only one thread is always doing work. I made the following changes:
I let the Woolworker store an Id
PoolWorker(int id){
this.threadId = id;
}
Before running I print the id of the worker.
System.out.println(this.threadId + " got new task");
r.run();
In WorkQueue constructor when creating the poolworkers I do:
for (int i = 0; i < nThreads; i++) {
threads[i] = new PoolWorker(i);
threads[i].start();
}
But it seems that that only thread 0 does any work, as the output is always:
0 got new task
Use queue.notifyAll() to start processing.
Currently you're using queue.notify(), which will only wake a single thread. (The big clue that pointed me to this was when you mentioned only a single thread was running.)
Also, synchronizing on Integer runCounter isn't doing what you think it's doing - runCounter++ is actually assigning a new value to the Integer each time, so you're synchronizing on a lot of different Integer objects.
On a side note, using raw threads and wait/notify paradigms is complicated and error-prone even for the best programmers - it's why Java introduced the java.util.concurrent package, which provide threadsafe BlockingQueue implementations and Executors for easily managing multithreaded apps.
Problem: While trying to retrieve values inside a recursive block in a phased manner, the execution gets hung.
Description: CountDownLatch & Object.wait are used to achieve the phased manner access of value inside the recursive block. But, the program hangs with following output:
2 < 16
3 < 16
4 < 16
5 < 16
Current total: 5
Inside of wait
Inside of wait
Program:
import java.util.concurrent.*;
public class RecursiveTotalFinder {
private static CountDownLatch latch1;
private static CountDownLatch latch2;
private static CountDownLatch latch3;
public static void main(String... args) {
latch1 = new CountDownLatch(1);
latch2 = new CountDownLatch(1);
latch3 = new CountDownLatch(1);
//Create object
TotalFinder tf = new TotalFinder(latch1,latch2,latch3);
//Start the thread
tf.start();
//Wait for results from TotalFinder
try {
latch1.await();
} catch(InterruptedException ie) {
ie.printStackTrace();
}
//Print the result after 5th iteration
System.out.println("Current total: "+tf.getCurrentTotal());
tf.releaseWaitLock();
tf.resetWaitLock();
//Wait for results again
try {
latch2.await();
} catch(InterruptedException ie) {
ie.printStackTrace();
}
//Print the result after 10th iteration
System.out.println("Current total: "+tf.getCurrentTotal());
tf.releaseWaitLock();
tf.resetWaitLock();
//Wait for results again
try {
latch3.await();
} catch(InterruptedException ie) {
ie.printStackTrace();
}
//Print the result after 15th iteration
System.out.println("Current total: "+tf.getCurrentTotal());
tf.releaseWaitLock();
tf.resetWaitLock();
}
}
class TotalFinder extends Thread{
CountDownLatch tfLatch1;
CountDownLatch tfLatch2;
CountDownLatch tfLatch3;
private static int count = 1;
private static final class Lock { }
private final Object lock = new Lock();
private boolean gotSignalFromMaster = false;
public TotalFinder(CountDownLatch latch1, CountDownLatch latch2,
CountDownLatch latch3) {
tfLatch1 = latch1;
tfLatch2 = latch2;
tfLatch3 = latch3;
}
public void run() {
findTotal(16);
}
//Find total
synchronized void findTotal(int cnt) {
if(count%5==0) {
if(count==5)
tfLatch1.countDown();
if(count==10)
tfLatch2.countDown();
if(count==15)
tfLatch3.countDown();
//Sleep for sometime
try {
Thread.sleep(3000);
} catch(InterruptedException ie) {
ie.printStackTrace();
}
//Wait till current total is printed
synchronized(lock) {
while(gotSignalFromMaster==false) {
try {
System.out.println(" Inside of wait");
lock.wait();
} catch(InterruptedException ie) {
ie.printStackTrace();
}
}
System.out.println("Came outside of wait");
}
}
count +=1;
if(count < cnt) {
System.out.println(count +" < "+cnt);
findTotal(cnt);
}
}
//Return the count value
public int getCurrentTotal() {
return count;
}
//Release lock
public void releaseWaitLock() {
//Sleep for sometime
try {
Thread.sleep(5000);
} catch(InterruptedException ie) {
ie.printStackTrace();
}
synchronized(lock) {
gotSignalFromMaster=true;
lock.notifyAll();
}
}
//Reset wait lock
public void resetWaitLock() {
gotSignalFromMaster = false;
}
}
Analysis:
In my initial analysis it looks like the wait is happening recursively eventhough notifyAll is invoked from the main program.
Help:
Why free lock using notfiyAll after a CountDownLatch didn't take effect? Need someone's help in understanding what exactly is happening in this program.
The main message about wait and notify that I got from JCIP was that I'd probably use them wrongly, so better to avoid using them directly unless strictly necessary. As such, I think that you should reconsider the use of these methods.
In this case, I think that you can do it more elegantly using SynchronousQueue. Perhaps something like this might work:
import java.util.concurrent.*;
public class RecursiveTotalFinder {
public static void main(String... args) throws InterruptedException {
SynchronousQueue<Integer> syncQueue = new SynchronousQueue<>();
//Create object
TotalFinder tf = new TotalFinder(syncQueue, 5);
//Start the thread
tf.start();
for (int i = 0; i < 3; ++i) {
System.out.println("Current total: " + syncQueue.take());
}
}
}
class TotalFinder extends Thread{
private final SynchronousQueue<Integer> syncQueue;
private final int syncEvery;
private int count;
public TotalFinder(SynchronousQueue<Integer> syncQueue,
int syncEvery) {
this.syncQueue = syncQueue;
this.syncEvery = syncEvery;
}
public void run() {
try {
findTotal(16);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
//Find total
void findTotal(int cnt) throws InterruptedException {
if((count > 0) && (count%syncEvery==0)) {
syncQueue.put(count);
}
count +=1;
if(count < cnt) {
System.out.println(count +" < "+cnt);
findTotal(cnt);
}
}
}
As to why your original approach doesn't work, it's because the main thread sets gotSignalFromMaster to true and then immediately back to false, and this happens before the other thread is able to check its value. If you stick a bit of a sleep into the resetWaitLock, it proceeds beyond the point where it currently hangs; however, it then hangs at the end instead of terminating.
Note that having to use Thread.sleep to wait for another thread to change some state is a poor approach - not least because it makes your program really slow. Using synchronization utilities leads to faster and much easier-to-reason-about program.
I have a program with this general structure:
init
create CyclicBarrier
initialise all threads, attaching to barrier
*start all threads*
wait for join
display stats
*start all threads*
perform calculation
await barrier
My problem is I need the threads' run() method to keep looping until a certain condition is met, but pausing after every iteration to let all threads synchronise.
I've already tried attaching a Runnable method to the barrier, but this ends up requiring the recreation and restarting of each thread, which isn't a very good solution.
I've also tried using the CyclicBarrier's reset() method, but this just seems to cause errors on the existing threads, even when executed after all threads have completed.
My question is:
-Is it possible to 'reset' a barrier and have all the barrier's threads follow the same conditions as they did before the first invocations of await()?
-Or is there another method I should be using to achieve this?
Thanks in advance
The barrier.wait() will suspend the threads. The barrier is already in the main thread, it does not need another. In your algorithm above you show the threads being restarted after displaying stats. You should not need to do this. If the recently awakened threads are in a loop they will go back into the barrier.wait() again.
Following #Totoro's answer, below is a little bit of example code which also incorporates the requirement "I need the threads' run() method to keep looping until a certain condition is met, pausing after every iteration to let all threads synchronise". That makes it complex pretty quick, but hopefully the program output will clarify the example code (or I should just make better examples).
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class BarrierCalc implements Runnable {
public static final int CALC_THREADS = 3;
private static final AtomicBoolean runCondition = new AtomicBoolean();
private static final AtomicBoolean stopRunning = new AtomicBoolean();
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(CALC_THREADS + 1);
for (int i = 0; i < CALC_THREADS; i++) {
new Thread(new BarrierCalc(barrier)).start();
}
try {
runCondition.set(true);
barrier.await();
showln(0, "STATS!");
barrier.await();
showln(0, "start looping 1");
Thread.sleep(200);
runCondition.set(false);
showln(0, "stop looping 1");
barrier.await();
runCondition.set(true);
barrier.await();
showln(0, "start looping 2");
Thread.sleep(100);
runCondition.set(false);
showln(0, "stop looping 2");
barrier.await();
stopRunning.set(true);
showln(0, "finishing");
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}
private static final AtomicInteger calcId = new AtomicInteger();
private CyclicBarrier barrier;
private int id;
public BarrierCalc(CyclicBarrier barrier) {
this.barrier = barrier;
id = calcId.incrementAndGet();
}
public void run() {
showln(id, "waiting for start");
try {
barrier.await(); // display stats
barrier.await(); // start running
int loopNumber = 0;
while (!stopRunning.get()) {
showln(id, "looping " + (++loopNumber));
while (runCondition.get()) {
Thread.sleep(10); // simulate looping
}
showln(id, "synchronizing " + loopNumber);
barrier.await();
showln(id, "synchronized " + loopNumber);
// give main thread a chance to set stopCondition and runCondition
barrier.await();
}
showln(id, "finished");
} catch (Exception e) {
e.printStackTrace();
}
}
private static final long START_TIME = System.currentTimeMillis();
public static void showln(int id, String msg) {
System.out.println((System.currentTimeMillis() - START_TIME) + "\t ID " + id + ": " + msg);
}
}
Keep in mind that program output might not be in the order expected: threads that are writing at the same time to one synchronized output (System.out) are given write-access in random order.
You can take a look at my example where I played with CyclicBarrier.Here each worker makes some calculation and at the barrier the condition is checked. If it meets the condition than all workers stop calculations, otherwise they continue:
class Solver {
private static final int REQUIRED_AMOUNT = 100;
private static final int NUMBER_OF_THREADS = 4;
AtomicInteger atomicInteger = new AtomicInteger();
AtomicBoolean continueCalculation = new AtomicBoolean(true);
final CyclicBarrier barrier;
public static void main(String[] args) {
new Solver();
}
class Worker implements Runnable {
int workerId;
Worker(int workerId) {
this.workerId = workerId;
}
public void run() {
try {
while(continueCalculation.get()) {
calculate(workerId);
barrier.await();
}
} catch (Exception ex) {
System.out.println("Finishing " + workerId);
}
}
}
public Solver() {
Runnable barrierAction = () -> {
if (done()) {
continueCalculation.set(false);
}
};
barrier = new CyclicBarrier(NUMBER_OF_THREADS, barrierAction);
List<Thread> threads = new ArrayList(NUMBER_OF_THREADS);
for (int i = 0; i < NUMBER_OF_THREADS; i++) {
Thread thread = new Thread(new Worker(i));
threads.add(thread);
thread.start();
}
}
private void calculate(int workerId) throws InterruptedException {
// Some long-running calculation
Thread.sleep(2000L);
int r = new Random().nextInt(12);
System.out.println("Worker #" + workerId + " added " + r +" = " + atomicInteger.addAndGet(r));
}
private boolean done() {
int currentResult = atomicInteger.get();
boolean collected = currentResult >= REQUIRED_AMOUNT;
System.out.println("=======================================================");
System.out.println("Checking state at the barrier: " + currentResult);
if (collected) {
System.out.println("Required result is reached");
}
System.out.println("=======================================================");
return collected;
}
}
I have a program that simulates Gates to a ship. They run in threads. The idea is to let them run and pause during a random moment in the run method to simulate persons passing. This is done by all threads, meanwhile the main thread is waiting for notification and checking if the ship is getting full when notified by the threads that they added a person passing through the gate the main thread checks again if the ship is full. The program has three classes:
A counter:
public class Counter {
private int currentValue[];
private int maxValue;
public Counter(int[] nrOfPeople, int max) {
currentValue = nrOfPeople;
currentValue[0] = 0;
maxValue = max;
}
public synchronized void addPersons(int nr_p) {
currentValue[0] += nr_p;
}
public synchronized int getValue() {
return currentValue[0];
}
public synchronized boolean isFull() {
if(currentValue[0] < maxValue)
return false;
return true;
}
}
A Gate Class:
public abstract class Gate implements Runnable {
int nrOfPassengers;
int gatenr;
int gatesize;
Counter c;
private Thread t;
private Random r;
private boolean blocked; /* suspends people from passing */
public Gate(Counter c, int nr) {
this.c = c;
gatenr = nr;
this.open();
r = new Random();
t = new Thread(this);
t.start();
}
public void setGatesize(int size) {
gatesize = size;
}
public void close() {
blocked = true;
}
public void open() {
blocked = false;
}
public int getNoOfPassangers() {
return nrOfPassengers;
}
public int getId() {
return gatenr;
}
#Override
public void run() {
while(!blocked) {
int waitTime = (r.nextInt(5) + 1) * 1000; /* between 1-5 seconds */
System.out.println("Person-Gate " + gatenr + ": adding one to " + c.getValue());
try {
/* bigger throughput => amount can vary */
if(gatesize > 1) {
int persons = r.nextInt(gatesize)+1;
c.addPersons(persons);
nrOfPassengers += persons;
} else {
c.addPersons(1);
nrOfPassengers++;
}
Thread.sleep(waitTime);
} catch (InterruptedException e) {
System.out.println("Person-Gate " + gatenr + ": was interrupted adding person");
e.printStackTrace();
}
System.out.println("Person-Gate " + gatenr + ": added one to " + c.getValue());
t.notify();
}
}
public void join() {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And a Simulator that runs the main method:
/*
* This class simulates cars and persons- entering a ferry.
*/
public class Simulator {
public static final int MAX = 30;
public static void main(String[] args) {
int nrOfPeople[] = new int[1]; /* array of size one for keeping count */
ArrayList<Gate> gates = new ArrayList<Gate>();
Counter counter = new Counter(nrOfPeople, MAX);
Thread mainThread = Thread.currentThread();
/* adding 3 person-gates */
for(int i=1; i<4; i++) {
gates.add(new PersonGate(counter, i));
}
/* let all gates work as long as passengers is under MAX */
while(!counter.isFull()) {
try {
mainThread.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Announcement: Ship is full!");
/* wait for child threads to finish */
for(Gate g: gates) {
g.close();
try {
g.join();
} catch (Exception e) { /* InterruptedException */
e.printStackTrace();
}
System.out.println(g.getNoOfPassangers() + " passed through gate nr " + g.getId());
System.out.println(counter.getValue() + " has passed in total");
}
}
}
Im getting a error
Person-Gate 1: adding one to 0
Person-Gate 2: adding one to 1
Person-Gate 3: adding one to 2
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at Simulator.main(Simulator.java:24)
Person-Gate 3: added one to 3Exception in thread "Thread-3"
Does anyone now whats going on?
You can only call wait and notify/notifyAll from within synchronized blocks.
t.notify();
You are notifying wrong monitor. This exception occurs, when you do not wrap monitor object with synchronize section. However, objects which you are using for notify and for wait methods are different. Create new Object() monitor and pass it to the constructor of Gate.
Also you can take a look at CountDownLatch, it does exactly what you are trying to achieve.
You must own the monitor of the object on which you call wait or notify. Meaning, you must be in a synchonize-Block, like
synchronized( objectUsedAsSynchronizer) {
while ( mustStillWait) {
objectUsedAsSynchronizer.wait();
}
}
This has been the subject of many other questions.