Semaphores not avoiding thread loss - java

this is my first question here so please bear with me.
I am currently working on a UNI assignment on multithreading and concurrency in Java where we are asked to implement various versions of a "Call Center" using different thread locking methods, with one of them being Semaphores. I'll get right into the code to show what my problem is:
Producer Class:
public final class Caller implements Runnable {
private final CallCenter callCenter;
public Caller(long id, CallCenter callCenter) {
this.callCenter = callCenter;
}
#Override
public void run() {
try {
callCenter.receive(new Call());
} catch(Exception ex) {
throw new RuntimeException(ex);
}
}
}
Consumer Class:
public final class Operator implements Runnable {
private final CallCenter callCenter;
private Call call;
public Operator(CallCenter callCenter) {
this.callCenter = callCenter;
}
#Override
public void run() {
try {
this.call = callCenter.answer();
} catch(InterruptedException ex) {
throw new RuntimeException(ex);
}
}
public Call getCall() {
return this.call;
}
}
Service:
import java.util.Queue;
import java.util.concurrent.Semaphore;
import java.util.LinkedList;
public final class BoundedCallCenterSemaphore implements BoundedCallCenter {
private final Queue<Call> pendingCalls = new LinkedList<Call>();
private Semaphore semaphore = new Semaphore(MAX_NUMBER_OF_PENDING_CALLS, true);
public void receive(Call call) throws Exception {
semaphore.acquire();
pendingCalls.add(call);
}
public Call answer() throws InterruptedException {
semaphore.release();
return pendingCalls.poll();
}
}
Call Implementation:
import java.util.concurrent.atomic.AtomicLong;
public final class Call {
private static final AtomicLong currentId = new AtomicLong();
private final long id = currentId.getAndIncrement();
public long getId() {
return id;
}
}
Disclaimer
I know I am probably not using the semaphore the way it is intended to be used, but reading the official docs an other blogs/answers does not help at all.
We have the following constraints: only modify the Service Class, solve using Semaphores and only use Semaphore.acquire() and Semaphore.receive() to avoid racing and busy waiting, no other method or thread-locking structure is allowed
Actual Problem:
I'll avoid posting here the entirety of the tests written by our professor, just know that 100 calls are sent to the Service, for simplicity each caller only calls once and each operator only responds once. When implementing the callcenter without semaphores you'll get busy waits generated by a while loop and concurrency is not well-managed as some calls can be answered twice or more if the different threads act simultaneously. The mission here is to eliminate busy waits and ensure each call is received and answered only once. I tried using semaphores as reported above, and while busy wait is eliminated some of the calls end up not being answered at all. Any advice on what I am doing wrong? How do I ensure that each and every call is answered only once?

In the end, I did it using three semaphores. The first semaphore new Semaphore(MAX_NUMBER_OF_PENDING_CALLS, true) guards the queue in the sense of blocking new entries when pendingCalls.size() >= MAX_NUMBER_OF_PENDING_CALLS . The second semaphore new Semaphore(1, true) guards the producer threads, allowing just one thread at a time to access the queue for adding operations. The third and last semaphore starts with no permits and waits for the first producer thread to insert the first call into the buffer new Semaphore(0, true) .
Code
public final class BoundedCallCenterSemaphore implements BoundedCallCenter {
private final LinkedList<Call> pendingCalls = new LinkedList<Call>();
static Semaphore receiver = new Semaphore(1, true);
static Semaphore storage = new Semaphore(MAX_NUMBER_OF_PENDING_CALLS, true);
static Semaphore operants = new Semaphore(0, true);
public void receive(Call call) throws Exception {
try {
storage.acquire();
}
catch (InterruptedException e)
{
}
try {
receiver.acquire();
}
catch (InterruptedException e)
{
}
synchronized (pendingCalls) {
pendingCalls.add(call);
operants.release();
}
}
public Call answer() throws InterruptedException {
try
{
operants.acquire();
}
catch (InterruptedException e)
{
}
Call call = null;
synchronized (pendingCalls) {
call = pendingCalls.poll();
storage.release();
receiver.release();
}
return call;
}
}

Related

Synchronized thread get/create via factory

I want to have multiple threads, each of them linked to a "group", which will do operations. Each of these threads, will in a loop look into a queue of Operations to do, and it is not empty, they will take next Operation and process it.
It is as simple as this:
public class GroupThreadManager {
private static ConcurrentHashMap<Long, GroupThread> threads = new ConcurrentHashMap<>();
private synchronized static void newOperation(Operation op) throws IOException {
final Long idGroup = op.getIdGroup();
if (!threads.containsKey(idGroup )) {
threads.put(idGroup , new GroupThread());
}
threads.get(idGroup ).start(op);
}
private synchronized static void interrupThread(Long id) {
if(threads.remove(id) == null) {
log.info("THIS SHOULDNT HAVE HAPPENED!!!!!");
}
}
}
public class GroupThread implements Runnable {
private Thread worker;
private ConcurrentLinkedQueue<Operation> operations = new ConcurrentLinkedQueue<>();
private Long idGroup;
public void start(Operation op) throws IOException {
addOperation(op);
if (worker == null) {
idGroup = op.getIdGroup();
worker = new Thread(this);
worker.start();
}
}
public synchronized void addOperation(Operation op) {
operations .add(user);
}
private synchronized int size() {
return operations.size();
}
public void run() {
while (size() > 0) {
operations.poll()
.compute() // do something here
}
GroupThreadManager.interrupThread(idUser);
}
}
If the run method was implemented with while (true) I would have no problem. The issue comes when I want that thread to process all the operations it has, and whenever it becomes out of operations, I want to make that Thread end. I have been trying to make proper synchronization to create/get the Thread from the GroupThreadManager, but I always come into either deadlocks, either Thread ending with new Operations to proceed due to missing synchronization.
The idea is that from another part of the program I can just call GroupThreadManager.newOperation(new Operation()) and this manager automatically gives me the correct thread for that groupId (contained in Operation), creating it, giving me the existing one, or stopping & deleting it when it detects there are no new operations for it

Unit testing asynchronous computation that has to be interrupted manually

I have got a class that records eyetracking data asynchronously. There are methods to start and stop the recording process. The data is collected in a collection and the collection can only be accessed if the recording thread has finished its work. It basically encapsulates all the threading and synchronizing so the user of my library doesn't have to do it.
The heavily shortened code (generics and error handling omitted):
public class Recorder {
private Collection accumulatorCollection;
private Thread recordingThread;
private class RecordingRunnable implements Runnable {
...
public void run() {
while(!Thread.currentThread().isInterrupted()) {
// fetch data and collect it in the accumulator
synchronized(acc) { acc.add(Eyetracker.getData()) }
}
}
}
public void start() {
accumulatorCollection = new Collection();
recordingThread = new Thread(new RecordingRunnable(accumulatorCollection));
recordingThread.start();
}
public void stop() {
recordingThread.interrupt();
}
public void getData() {
try {
recordingThread.join(2000);
if(recordingThread.isAlive()) { throw Exception(); }
}
catch(InterruptedException e) { ... }
synchronized(accumulatorCollection) { return accumulatorCollection; }
}
}
The usage is quite simple:
recorder.start();
...
recorder.stop();
Collection data = recorder.getData();
My problem with the whole thing is how to test it. Currently i am doing it like this:
recorder.start();
Thread.sleep(50);
recorder.stop();
Collection data = recorder.getData();
assert(stuff);
This works, but it is non-deterministic and slows down the test suite quite a bit (i marked these tests as integration tests, so they have to be run separately to circumvent this problem).
Is there a better way?
There is a better way using a CountDownLatch.
The non-deterministic part of the test stems from two variables in time you do not account for:
creating and starting a thread takes time and the thread may not have started executing the runnable when Thread.start() returns (the runnable will get executed, but it may be a bit later).
the stop/interrupt will break the while-loop in the Runnable but not immediately, it may be a bit later.
This is where a CountDownLatch comes in: it gives you precise information about where another thread is in execution. E.g. let the first thread wait on the latch, while the second "counts down" the latch as last statement within a runnable and now the first thread knows that the runnable finished. The CountDownLatch also acts as a synchronizer: whatever the second thread was writing to memory, can now be read by the first thread.
Instead of using an interrupt, you can also use a volatile boolean. Any thread reading the volatile variable is guaranteed to see the last value set by any other thread.
A CountDownLatch can also be given a timeout which is useful for tests that can hang: if you have to wait to long you can abort the whole test (e.g. shutdown executors, interrupt threads) and throw an AssertionError. In the code below I re-used the timeout to wait for a certain amount of data to collect instead of 'sleeping'.
As an optimization, use an Executor (ThreadPool) instead of creating and starting threads. The latter is relative expensive, using an Executor can really make a difference.
Below the updated code, I made it runnable as an application (main method). (edit 28/02/17: check maxCollect > 0 in while-loop)
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class Recorder {
private final ExecutorService executor;
private Thread recordingThread;
private volatile boolean stopRecording;
private CountDownLatch finishedRecording;
private Collection<Object> eyeData;
private int maxCollect;
private final AtomicBoolean started = new AtomicBoolean();
private final AtomicBoolean stopped = new AtomicBoolean();
public Recorder() {
this(null);
}
public Recorder(ExecutorService executor) {
this.executor = executor;
}
public Recorder maxCollect(int max) { maxCollect = max; return this; }
private class RecordingRunnable implements Runnable {
#Override public void run() {
try {
int collected = 0;
while (!stopRecording) {
eyeData.add(EyeTracker.getData());
if (maxCollect > 0 && ++collected >= maxCollect) {
stopRecording = true;
}
}
} finally {
finishedRecording.countDown();
}
}
}
public Recorder start() {
if (!started.compareAndSet(false, true)) {
throw new IllegalStateException("already started");
}
stopRecording = false;
finishedRecording = new CountDownLatch(1);
eyeData = new ArrayList<Object>();
// the RecordingRunnable created below will see the values assigned above ('happens before relationship')
if (executor == null) {
recordingThread = new Thread(new RecordingRunnable());
recordingThread.start();
} else {
executor.execute(new RecordingRunnable());
}
return this;
}
public Collection<Object> getData(long timeout, TimeUnit tunit) {
if (started.get() == false) {
throw new IllegalStateException("start first");
}
if (!stopped.compareAndSet(false, true)) {
throw new IllegalStateException("data already fetched");
}
if (maxCollect <= 0) {
stopRecording = true;
}
boolean recordingStopped = false;
try {
// this establishes a 'happens before relationship'
// all updates to eyeData are now visible in this thread.
recordingStopped = finishedRecording.await(timeout, tunit);
} catch(InterruptedException e) {
throw new RuntimeException("interrupted", e);
} finally {
stopRecording = true;
}
// if recording did not stop, do not return the eyeData (could stil be modified by recording-runnable).
if (!recordingStopped) {
throw new RuntimeException("recording");
}
// only when everything is OK this recorder instance can be re-used
started.set(false);
stopped.set(false);
return eyeData;
}
public static class EyeTracker {
public static Object getData() {
try { Thread.sleep(1); } catch (Exception ignored) {}
return new Object();
}
}
public static void main(String[] args) {
System.out.println("Starting.");
ExecutorService exe = Executors.newSingleThreadExecutor();
try {
Recorder r = new Recorder(exe).maxCollect(50).start();
int dsize = r.getData(2000, TimeUnit.MILLISECONDS).size();
System.out.println("Collected " + dsize);
r.maxCollect(100).start();
dsize = r.getData(2000, TimeUnit.MILLISECONDS).size();
System.out.println("Collected " + dsize);
r.maxCollect(0).start();
Thread.sleep(100);
dsize = r.getData(2000, TimeUnit.MILLISECONDS).size();
System.out.println("Collected " + dsize);
} catch (Exception e) {
e.printStackTrace();
} finally {
exe.shutdownNow();
System.out.println("Done.");
}
}
}
Happy coding :)

Exception in thread "Thread-0" java.util.NoSuchElementException?

I am new to using threads. In another class an instance of the ConnectionMaster class is created and started (extends thread). A Client object is given to the ConnectionMaster object which adds it to the list. The overridden run() method of the Thread class essentially listens for a client to be added to the list. Indeed it does listen and "hears" when a Client object is added to the list. However, although .hasNext() returns true .Next() causes an exception. What am I doing wrong?
The following methods are from class ConnectionMaster which extends Thread:
Constructor
public ConnectionMaster(){
clients = new Vector<>();
listIterator = clients.listIterator();
}
Public method for adding client objects to the list
#Override
public synchronized void addClient(Client client) {
listIterator.add(client);
}
This is the overridden thread method of the class Thread. It consistently checks for elements added to the list.
#Override
public void run(){
while(true){
while(listIterator.hasNext()){
processClient(listIterator.next()); //this is where error occurs
listIterator.remove();
}
while(listIterator.hasPrevious()){
processClient(listIterator.previous());
listIterator.remove();
}
}
}
////////////////////////////////UPDATE////////////////////////////////////
Thank You OldCurmudgeon and Stephen C.
Based on your feedback, my code has been modified thus:
Constructor
public ConnectionMaster(){
clients = new ArrayBlockingQueue<Client>(1024);
}
Method for receiving client objects
#Override
public synchronized void addClient(Client client) {
try {
clients.put(client);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Listener
#Override
public void run(){
while(true){
try {
processClient((Client)clients.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
This is a very strange way to implement Producer/Consumer. The usual way is to use a BlockingQueue.
public class TwoThreads {
public static void main(String args[]) throws InterruptedException {
System.out.println("TwoThreads:Test");
new TwoThreads().test();
}
// The end of the list.
private static final Integer End = -1;
static class Producer implements Runnable {
final BlockingQueue<Integer> queue;
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
#Override
public void run() {
try {
for (int i = 0; i < 1000; i++) {
queue.add(i);
Thread.sleep(1);
}
// Finish the queue.
queue.add(End);
} catch (InterruptedException ex) {
// Just exit.
}
}
}
static class Consumer implements Runnable {
final BlockingQueue<Integer> queue;
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
#Override
public void run() {
boolean ended = false;
while (!ended) {
try {
Integer i = queue.take();
ended = i == End;
System.out.println(i);
} catch (InterruptedException ex) {
ended = true;
}
}
}
}
public void test() throws InterruptedException {
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
Thread pt = new Thread(new Producer(queue));
Thread ct = new Thread(new Consumer(queue));
// Start it all going.
pt.start();
ct.start();
// Wait for it to finish.
pt.join();
ct.join();
}
}
What am I doing wrong?
Quite a lot actually.
First thing you are doing wrong is (apparently) using an ListIterator object in multiple threads. The ListIterator and Iterator implementations for Vector are not thread-safe1, so what you are doing is potentially hazardous.
The second thing is that even if the iterators / list iterators were thread-safe, you are performing a sequence of operations (e.g. hasNext, next, remove) without doing anything to ensure that the sequence of operations is performed in a way that is threadsafe. There is a distinct possibility that two threads could be performing the same sequence simultaneously on the shared iterator, and that one could interfere with the other.
I'm not sure what to suggest in order to fix your code. Two threads sharing an iterator is not going to work.
It would probably be better to ditch it, and use some kind of Queue as suggested by #OldCurmugeon.
Either problem 1 or problem 2 (as outlined above) could give rise to NoSuchElement exceptions.
1 - This is apparent from examining the source code - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Vector.java#Vector.ListItr .

Producer-consumers(many). Consumers take and put into the shared queue

I made a producer-consumer program. It's just a program in core java without any GUI(Swing or SWT). It has one producer who put objects into the queue.
Also there is a few consumers who must add some staff(for example String) into Every object in that shared queue. So, every consumer must handle every object in a shared queue.
In this case - every BookShelf must have items from All consumers in "books" ArrayList. consumers.
Question: What condition should I use in consumers to finish their threads correctly?
Here are the code fragments of the program. Maybe I implemented it in wrong way.
Here is an object for the queue:
public class BookShelf {
private int id;
private String name;
private int height;
private int weigh;
List<String> books = Collections.synchronizedList(new ArrayList<String>());
public BookShelf(int id, String name) {
this.id = id;
this.name = name;
}
public void addBook(String book) {
books.add(book);
}
public boolean eq(String book) {
synchronized (books) {
for (String b: books) {
if (b.equalsIgnoreCase(book)) {
return true;
}
}
}
return false;
}
other setters and getters..
}
Here is the producer class:
public class Producer implements Runnable {
private BlockingQueue myQueue;
public Producer(BlockingQueue myQueue) {
this.myQueue = myQueue;
}
public void run() {
for(int i=0; i<7; i++){
try {
System.out.println("Produced: " + i);
BookShelf myBookShelf = new BookShelf(i, "book #" + i);
myQueue.put(myBookShelf);
} catch (InterruptedException ex) {
//Proper handle
}
}
}
}
Here is one of consumers class:
public class Consumer implements Runnable {
private BlockingQueue myQueue;
public Consumer(BlockingQueue myQueue) {
this.myQueue = myQueue; }
public void run() {
while(true){
try {
BookShelf tempBookShelf = (BookShelf) myQueue.take();
//eq() is my method to check if ArraList has a book.
if (tempBookShelf.eq("Abc book")) {
System.out.println("It already has book");
myQueue.put(tempBookShelf);
Thread.sleep(2000);
} else {
tempBookShelf.addBook("Abc book");
myQueue.put(tempBookShelf);
Thread.sleep(2000);
}
} catch (InterruptedException ex) {
//Proper handle
}
}
}
}
Here is main class:
public class ProducerConsumerTest {
public static void main(String[] args) {
BlockingQueue sharedQueue = new LinkedBlockingQueue();
Thread prodThread = new Thread(new Producer(sharedQueue));
Thread consThread = new Thread(new Consumer(sharedQueue));
Thread consThread2 = new Thread(new Consumer2(sharedQueue));
prodThread.start();
consThread.start();
consThread2.start();
}
}
Register each consumer with the producer. Each consumer has its own queue and the producer puts the object into all the queues. Each consumer then process on the same instance of the object.
public interface Consumer{
public void process(BookShelf bs);
}
public class Producer implements Runnable{
private final List<Consumer> consumers = new CopyOnWriteArrayList<Consumer>(); // thread safe but not efficient with lots of changes
public void register(Consumer c){
consumers.add(c); // thread safe
}
public void run(){
for(;;){
BookShelf bs = generateBookShelfByWhateverMeans();
for (Consumer c : consumers){
c.process(bs);
}
}
}
}
public class BookShelfConsumer implements Runnable, Consumer{
private final BlockingQueue<BookShelf> queue = new LinkedTransferQueue<BookShelf>(); // unbounded & thread safe
public void process(BookShelf bs){
queue.offer(bs); // non-blocking
}
public void run(){
for(;;){
BookShelf bs = queue.take(); // blocks until got object or interrupted
// catch InterruptedException
// do whatever this consumer is supposed to do with the object
}
}
}
I would try using SwingWorker instead. It has a done() method that is executed when it's finished. See this page for some code examples.
If it's not Swing you are using, there is a similar function in Swt called Jobs. Check this page for examples. It also has a done() method being executed when the job is done.
Also there is a few(N number) consumers who must add some staff(for example String) into Every object in that shared queue
I assume you mean every consumer must add their thing to every object which ever enters the queue. In that case, this is not a producer-consumer problem, this is more like an observer-observable problem. Basically, when a new BookShelf is created, that is the Observable. All of the Observers should be notified about the BookShelf and given the opportunity to add their own Book.
I recommend using a ConcurrentLinkedQueue in Bookshelf instead of a synchronized list - it's lock free (doesn't need to be synchronized) and will probably be more efficient.
To end your consumers, change their while(true) loops to while(!cancel) loops. Give each consumer a cancel boolean as an instance variable that initializes to false, and give them a cancel() method that sets cancel to true. Call cancel() on your consumers when you're done with them. If you will always be canceling all of your consumers at once (instead of selectively canceling some but not others), then you can use a static cancel instead of an instance cancel.

Java signal/event mechanism to indicate some value is available

I have a generator class that owns a Thread in which a number of "records" to be generated is determined, then generates that many records (which get placed in a BlockingQueue for retrieval by another thread).
I'd like the other thread to know how many records are going to be generated (for sensible progress reporting among other things).
It seems Future gives me exactly the interface I'm after, but I'm new to Java, and not sure of the idiomatic way of implementing it.
My background is in C++/Win32, so I'd normally use a win32 "Event" (as created by CreateEvent(0, true, false, 0), with SetEvent and WaitForSingleObject for my signal and wait implementations). I've noticed Java has a CountDownLatch, but this somehow feels heavier than what I'm after (somewhat akin to using an int when I really want a boolean), and it seems unintuitive for this purpose (to me, anyway).
So here's my code using CountDownLatch and a Future. I've distilled my real code down a bit here (removed irrelevant implementation details and ignoring all error handling).
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public abstract class Generator {
private CountDownLatch numRecordsSignal = new CountDownLatch(1);
private int numRecords;
private BlockingQueue<Record> queue = new LinkedBlockingQueue<Record>();
public Generator() {
new Thread(new Runnable() {
#Override
public void run() {
numRecords = calculateNumRecords();
numRecordsSignal.countDown();
for (Record r : generateRecords()) {
try {
queue.put(r);
} catch (InterruptedException e) {
// [ ... snip ... ]
}
}
}
}).start();
}
public Future<Integer> numRecords() {
return new Future<Integer>() {
// Ignore cancel for now (It wouldn't make sense to cancel
// just this part of the Generator's work, anyway).
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
public Integer get() throws InterruptedException {
numRecordsSignal.await();
return numRecords;
}
public Integer get(long timeout, TimeUnit unit)
throws InterruptedException {
numRecordsSignal.await(timeout, unit);
return numRecords;
}
public boolean isCancelled() {
return false;
}
public boolean isDone() {
// Since we can't cancel, just check the state of the
// signal
return numRecordsSignal.getCount() == 0;
}
};
}
public Record nextRecord() throws InterruptedException {
return queue.take();
}
/** --- Boring stuff below this line --- */
public interface Record { }
protected abstract int calculateNumRecords();
protected abstract Iterable<Record> generateRecords();
}
Now for my actual questions:
Is there a better mechanism than CountDownLatch for single-shot signalling?
I want callers to be able to either wait or poll on the result, but don't need them to be able to cancel the operation. Is Future the right way to expose this stuff?
Does any of this stuff look particularly "un-Java"? Am I on the wrong track completely?
Edit:
Just to clarify, I expect the caller to be able to do the following:
Generator gen = new Generator();
Integer numRecords = gen.numRecords().get(); // This call might block waiting for the result
numRecords = gen.numRecords().get(); // This call will never block, as the result is already available.
It's just a slow-to-initialise value I'm trying to implement. Once the "initialised" condition is met, it should latch. The value doesn't get re-evaluated once it's known.
Side comment
You should not start a thread in a constructor - it is very conceivable that the Generator object is not fully created when the thread starts, and the countdown latch could well be null for example. You can create the thread in the constructor, but should start it in a seperate method. Your calling code would become:
Generator g = new Generator();
g.start();
Your question
You are reimplementing a Future yourself, which is not necessary nor desirable in my opinion. I would redesign the class and make Generator implement Callable<Integer> and run it through an executor. That provides you with several things:
remove the threading logic from the Generator, which enables you a more efficient management of your threads at a higher level in your call stack
the integer is returned via the future in your calling code and you rely on the JDK to handle the implementation
I have assumed that it's ok to first populate the queue then return the integer
you can call future.get() as many times as you want - it will only block the first time it is called.
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Integer> future = executor.submit(new GeneratorImpl()); //a concrete implementation of Generator
int numRecords = 0;
try {
numRecords = future.get(); //you can use a get with timeout here
} catch (ExecutionException e) {
//an exception happened in Generator#call()
} catch (InterruptedException e) {
//handle it
}
//don't forget to call executor.shutdown() when you don't need it any longer
}
public abstract class Generator implements Callable<Integer> {
private BlockingQueue<Record> queue = new LinkedBlockingQueue<Record>();
#Override
public Integer call() {
int numRecords = calculateNumRecords();
for (Record r : generateRecords()) {
try {
queue.put(r);
} catch (InterruptedException e) {
// [ ... snip ... ]
}
}
return numRecords;
}
public Record nextRecord() throws InterruptedException {
return queue.take();
}
/**
* --- Boring stuff below this line ---
*/
public interface Record {
}
protected abstract int calculateNumRecords();
protected abstract Iterable<Record> generateRecords();
}
EDIT
If you need to return numRecods asap, you can populate your queue in a separate thread:
public Integer call() {
int numRecords = calculateNumRecords();
new Thread(new Runnable() {
#Override
public void run() {
for (Record r : generateRecords()) {
try {
queue.put(r);
} catch (InterruptedException e) {
// [ ... snip ... ]
}
}
}
}).start(); //returns immediately
return numRecords;
}
The standard Java equivalents of "WaitOnSingleEvent()" and "SetEvent()" for Java threads are "wait()", "notify()" and "notifyAll()".
After looking at implementing my own signal mechanism and following the bread-crumb trail left by others doing the same thing, I came across the javadoc for AbstractQueuedSynchronizer, which includes a code snippet for a "BooleanLatch", which perfectly meets my needs:
class BooleanLatch {
private static class Sync extends AbstractQueuedSynchronizer {
boolean isSignalled() { return getState() != 0; }
protected int tryAcquireShared(int ignore) {
return isSignalled()? 1 : -1;
}
protected boolean tryReleaseShared(int ignore) {
setState(1);
return true;
}
}
private final Sync sync = new Sync();
public boolean isSignalled() { return sync.isSignalled(); }
public void signal() { sync.releaseShared(1); }
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
}
Doing a bit more searching, I found that a number of frameworks include a BooleanLatch (Apache Qpid being one). Some implementations (such as Atlassian's), are auto-resetting, which would make them inappropriate for my needs.
Standard observer notification pattern can be helpful here, if i understood your problem correctly.
For one shot signalling in this scenario Semaphore is better as it remembers the "signal".
Condition object [wait() is on a condition] won't remember the signal.
Semaphore numRecordsUpdated = new Semaphore(0);
In Generator
numRecordsUpdated.release();
In consumer
numRecordsUpdated.acquire();

Categories