java assignment synchronization producer consumer - java

I've written a Multithreading code for producer consumer problem in which I've written synchronized block inside the run method of consumer and producer thread which takes lock on shared list(I assumed)
So the point of question is that, will there be locking on the list, because as per each thread will have their own synchronized block but they are sharing the same list instance
public class Main {
static boolean finishFlag=false;
final int queueSize = 20;
List<Integer> queue = new LinkedList<>();
Semaphore semaphoreForList = new Semaphore(queueSize);
public Main(int producerCount,int consumerCount) {
while(producerCount!=0) {
new MyProducer(queue,semaphoreForList,queueSize).start(); //produces the producer
producerCount--;
}
while(consumerCount!=0) {
new MyConsumer(queue,semaphoreForList,queueSize).start(); //produces the consumer
consumerCount--;
}
}
public static void main(String args[]) {
/*
* input is from command line 1st i/p is number of producer and 2nd i/p is number of consumer
*/
try {
Main newMain = new Main(Integer.parseInt(args[0]),Integer.parseInt(args[1]));
try {
Thread.sleep(30000);
}
catch(InterruptedException e) {
}
System.out.println("exit");
finishFlag=true;
}
catch(NumberFormatException e) {
System.out.println(e.getMessage());
}
}
}
class MyProducer extends Thread{
private List<Integer> queue;
Semaphore semaphoreForList;
int queueSize;
public MyProducer(List<Integer> queue, Semaphore semaphoreForList,int queueSize) {
this.queue = queue;
this.semaphoreForList = semaphoreForList;
this.queueSize = queueSize;
}
public void run() {
while(!Main.finishFlag) {
try {
Thread.sleep((int)(Math.random()*1000));
}
catch(InterruptedException e) {
}
try {
if(semaphoreForList.availablePermits()==0) {//check if any space is left on queue to put the int
System.out.println("no more spaces left");
}
else {
synchronized(queue) {
semaphoreForList.acquire(); //acquire resource by putting int on the queue
int rand=(int)(Math.random()*10+1);
queue.add(rand);
System.out.println(rand+" was put on queue and now length is "+(queueSize-semaphoreForList.availablePermits()));
}
}
}
catch(InterruptedException m) {
System.out.println(m);
}
}
}
}
public class MyConsumer extends Thread{
private List<Integer> queue; //shared queue by consumer and producer
Semaphore semaphoreForList;
int queueSize;
public MyConsumer(List<Integer> queue, Semaphore semaphoreForList,int queueSize) {
this.queue = queue;
this.semaphoreForList = semaphoreForList;
this.queueSize = queueSize;
}
public void run() {
while(!Main.finishFlag) {//runs until finish flag is set to false by main
try {
Thread.sleep((int)(Math.random()*1000));//sleeps for random amount of time
}
catch(InterruptedException e) {
}
if((20-semaphoreForList.availablePermits())==0) {//checking if any int can be pulled from queue
System.out.println("no int on queue");
}
else {
synchronized(queue) {
int input=queue.remove(0);//releases the resource(position in queue) by pulling the int out of the queue and computing factorial
semaphoreForList.release();
int copyOfInput=input;
int fact=1;
while(copyOfInput!=0) {
fact = fact*copyOfInput;
copyOfInput--;
}
System.out.println(input+" was pulled out from queue and the computed factorial is "+fact+
" the remaining length of queue is "+(queueSize-semaphoreForList.availablePermits()));
}
}
}
}
}

I would rather recommend to use the java.lang.Object methods wait() and notify() to create a consumer-producer algorithm. Using this approach the queue won't be blocked by endlessly repeating and unnecessary synchronized statements which I think is a more performant and "event driven" solution.
This link might be helpful -
https://www.geeksforgeeks.org/producer-consumer-solution-using-threads-java/

Yes, the mutex/monitor is associated with the Java Object instance, which is the shared list in this instance. Which means all threads lock same mutex (associated with queue, and are synchronized through this.
So the good part: You program is actually thread-safe.
However the additional semaphore actually doesn't make a lot of sense in a variety of ways:
The checks (e.g. for availablePermits) happen outside of the lock, and are therefore only a best-guess about the state of your queue. It could be different shortly afterwards.
Trying to acquire a semaphore inside a lock, which can only be released inside the same lock, looks like a guaranteed recipe for a deadlock.
As AnDus has mentioned, this could probably be better solved via using the wait and notify methods which act as a condition variable. Most likely you need even two, one to unblock producers and one to unblock consumers.
In general, if this is not a coding exercise, use a class which already implements your desired functionality. In this case, java.util.concurrent.BlockingQueue seems like what you want.

Related

Monitor/Java synchronized methods, how to schedule an activity in a non-blocking way?

So, basically the whole idea is that I have to simulate the entrance of a school. N students queue at four turnstiles and then they join a random classroom. When the first student joins that classroom a lecture starts and lasts for a time T, after which the lecture ends and students go home.
I'm specifically struggling at the "lasts for a time T" part. Here is what I tried:
StudentThread:
#Override
public void run() {
try {
/** Some uninteresting code**/
classroom.joinClass(studentID);
}catch(InterruptedException e) {
}
}
Classroom:
private static final int LECTURE_DURATION = 3000;
public synchronized void joinClass(UUID student) throws InterruptedException {
this.students.add(student);
if( students.size() == 1 ) {
lecture = true;
new ScheduledThreadPoolExecutor(1).schedule(new Runnable() {
#Override
public void run() {
while( !students.isEmpty() )
students.remove(0);
lecture = false;
notifyAll();
}
}, LECTURE_DURATION, TimeUnit.MILLISECONDS);
}
while( lecture )
wait();
}
The apparent problem with this solution is that the first student joining a classroom will block the access to all the others, basically never leaving the joinClass method until the lecture ends. I assume it's because of that schedule call. I also can only use synchronized methods, no semaphores otherwise it would've been relatively easy. What should I do in this case?
You should not create a new ScheduledThreadPoolExecutor within the method. An executor is supposed to be reused. And you should call shutdown() on it once you really don’t need it anymore.
But more important is that, since the scheduled action is performed by a different thread, it must use synchronized when accessing the mutable state.
This leads to the point you’re missing about wait(). The only way for the condition you’re waiting for to correctly become fulfilled, is by having another thread performing the necessary steps within a synchronized block and calling notify() or notifyAll(), both methods insisting on being called within that synchronized block.
This can only work, when wait() releases the lock, so the other thread can acquire it and do the duty. And that’s precisely what wait does:
This method causes the current thread (referred to here as T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object. Note that only the locks on this object are relinquished; any other objects on which the current thread may be synchronized remain locked while the thread waits.
Thread T then becomes disabled for thread scheduling purposes and lies dormant until one of the following occurs:
…
The thread T is then removed from the wait set for this object and re-enabled for thread scheduling. It competes in the usual manner with other threads for the right to synchronize on the object; once it has regained control of the object, all its synchronization claims on the object are restored to the status quo ante - that is, to the situation as of the time that the wait method was invoked. Thread T then returns from the invocation of the wait method. Thus, on return from the wait method, the synchronization state of the object and of thread T is exactly as it was when the wait method was invoked.
Note that the documentation of the no-arg wait method redirects to the wait(long,int) documentation shown above
So the issue of your code is not that the initiating thread synchronizes but that the pool’s thread does not.
static final ScheduledThreadPoolExecutor EXEC = new ScheduledThreadPoolExecutor(1);
public synchronized void joinClass(UUID student) throws InterruptedException {
this.students.add(student);
if(students.size() == 1) {
lecture = true;
EXEC.schedule(new Runnable() {
#Override
public void run() {
synchronized(OuterClassName.this) {
students.clear();
lecture = false;
OuterClassName.this.notifyAll();
}
}
}, LECTURE_DURATION, TimeUnit.MILLISECONDS);
}
while(lecture) wait();
}
As a side note, there is no reason to remove single elements in a loop to empty a list, clear() does the job. In case of an ArrayList, repeatedly calling remove(0) is the worst way to clear it.
It’s also important to keep in mind that an inner class instance is a different object than the outer class instance. It’s simpler when using a lambda expression:
public synchronized void joinClass(UUID student) throws InterruptedException {
this.students.add(student);
if(students.size() == 1) {
lecture = true;
EXEC.schedule(() -> {
synchronized(this) {
students.clear();
lecture = false;
notifyAll();
}
}, LECTURE_DURATION, TimeUnit.MILLISECONDS);
}
while(lecture) wait();
}
No idea if this going to solve your problem but it might give you an idea.
public class Main
{
public static void main(String[] args) throws Exception
{
Classroom classroom = new Classroom();
Student studentA = new Student("Student A", classroom);
Student studentB = new Student("Student B", classroom);
Student studentC = new Student("Student C", classroom);
Student studentD = new Student("Student D", classroom);
studentA.enterClass();
Thread.sleep(1000L); //1000 m/s early.
classroom.start();
Thread.sleep(1000L); //1 second late.
studentB.enterClass();
Thread.sleep(500L); //Late for 1.5 seconds.
studentC.enterClass();
classroom.join();
Thread.sleep(2000L); //Class has ended.
studentD.enterClass();
System.out.println("Main Thread");
}
}
class Student implements Runnable
{
public String name;
private Classroom classroom;
public Thread thread;
Student(String name, Classroom classroom)
{
this.name = name;
this.classroom = classroom;
thread = new Thread(this);
}
public void enterClass()
{
thread.start();
}
public synchronized void exitClass()
{
this.notify();
}
#Override
public void run()
{
try {
System.out.println(name + " entering the class.");
classroom.joinClass(this);
synchronized(this) {
while(!classroom.hasEnded) this.wait();
}
System.out.println(name + " existing the class.");
} catch(Exception e) {}
}
}
class Classroom implements Runnable
{
private static final long LECTURE_DURATION = 3000L;
private Thread thread;
public volatile boolean hasEnded;
private List<Student> students;
Classroom()
{
students = new ArrayList<Student>();
thread = new Thread(this);
}
public void start()
{
thread.start();
}
public void join() throws Exception
{
thread.join();
}
#Override
public void run()
{
System.out.println("Class starting...");
try {
Thread.sleep(LECTURE_DURATION);
} catch(Exception e) {}
hasEnded = true;
System.out.println("Class ended");
for(Student s : students) s.exitClass();
}
public void joinClass(Student student) throws Exception
{
if(!hasEnded) {
System.out.println(student.name + " joins the class.");
students.add(student);
}
}
}
Here is the output. It may vary in your system.
Student A entering the class.
Student A joins the class.
Class starting...
Student B entering the class.
Student B joins the class.
Student C entering the class.
Student C joins the class.
Class ended
Student B existing the class.
Student A existing the class.
Student C existing the class.
Main Thread
Student D entering the class.
Student D existing the class.

spring boot and Executor Service

I am using spring boot
public interface StringConsume extends Consumer<String> {
default public void strHandel(String str) {
accept(str);
}
}
Impl
#Component("StrImpl")
public class StringConsumeImpl implements StringConsume {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(500);
final ExecutorService exService = Executors.newSingleThreadExecutor();
Future<?> future = CompletableFuture.completedFuture(true);
#Override
public void accept(String t) {
try {
queue.put(t);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (null != queue.peek()) {
if (future.isDone()) {
future = exService.submit(() -> queue.take());
}
}
}
}
Class
#Component
public class Test {
#Resource(name="StrImpl")
private #Autowired StringConsume handler;
public void insertIntoQueue(String str) {
handler.accept(str);
}
}
In StringConsumeImpl , do I need synchronized while loop? and suppose five time StringConsumeImpl class called, then do while loop will create 5 process or only 1 process ? and what is the best replacement of while loop in StringConsumeImpl , if any ?
There are some problems with that code.
First of all, the consumer doesn't really "consume" anything, it just adds the string to the queue then takes it back out. Let's say for the sake of the argument that it also "consumes" it by printing it to console or something.
Secondly, the consumer will only get called once due to the loop unless it is running in a thread of its own. Eg if you do
public static void main(String[]args) {
StringConsume consumer = new StringConsumeImpl();
consumer.accept("hello");
}
The consumer will put "hello" into the queue, take it out immediately and then stay in the loop, waiting for more elements to take out; however, no one is there to actually add any.
The usual concept of doing what it looks like you're trying to do is "producer/consumer". This means that there is a "producer" that puts items into a queue and a "consumer" taking them out and doing stuff with them.
So in your case what your class does is "consume" the string by putting it into the queue, making it a "producer", then "consuming" the string by taking it back out of the queue. Of course, there's also the "actual" producer of the string, ie the class calling this.
So in general you'd do something like this:
/** Produces random Strings */
class RandomStringProducer {
Random random = new Random();
public String produceString() {
return Double.toString(random.nextDouble());
}
}
/** Prints a String */
class PrintConsumer implements StringConsume {
public void accept(String s) { System.out.println(s); }
}
/** Consumes String by putting it into a queue */
class QueueProducer implements StringConsume {
BlockingQueue<String> queue;
public QueueProducer(BlockingQueue<String> q) { queue = q; }
public void accept(String s) {
queue.put(s);
}
}
public static void main(String[] args) {
// the producer
RandomStringProducer producer = new RandomStringProducer();
// the end consumer
StringConsume printConsumer = new PrintConsumer();
// the queue that links producer and consumer
BlockingQueue<String> queue = new ArrayBlockingQueue<>();
// the consumer putting strings into the queue
QueueProducer queuePutter = new QueueProducer(queue);
// now, let's tie them together
// one thread to produce strings and put them into the queue
ScheduledExecutorService producerService = Executors.newScheduledThreadPool(1);
Runnable createStringAndPutIntoQueue = () -> {
String created = producer.createString();
queuePutter.consume(created);
};
// put string into queue every 100ms
producerService.scheduleAtFixedRate(createStringAndPutIntoQueue, 100, TimeUnit.MILLISECONDS);
// one thread to consume strings
Runnable takeStringFromQueueAndPrint = () -> {
while(true) {
String takenFromQueue = queue.take(); // this will block until a string is available
printConsumer.consume(takenFromQueue);
}
};
// let it run in a different thread
ExecutorService consumerService = Executors.newSingleThreadExecutor();
consumerService.submit(takeStringFromQueueAndPrint);
// this will be printed; we are in the main thread and code is still being executed
System.out.println("the produce/consume has started");
}
So when you run this, there will be three threads: the main thread, the producer thread and the consumer thread. The producer and consumer will be doing their thing concurrently, and the main thread will also continue to run (as exemplified by the System.out.println in the last line).

Access thread variable that changes from main thread

So, I am new to threads, and I'm still learning how everything works. So, I couldn't find an answer that would provide an explanation for my problem (to my level of understanding).
I have a Runnable class that looks like so:
public class Request implements Runnable {
private Boolean ok = true;
public synchronized void setOk(Boolean ok) {
this.ok = ok;
}
public synchronized Boolean getOk() {
return ok;
}
private synchronized void foo() {
//if something happens
setOk(false);
}
#Override
public void run() {
while (true)
foo();
}
}
And then I have another class that does the following:
private static Request request;
private static void spawnThreads() {
ExecutorService e = new Executors.newFixedThreadPool(4);
request = new Request();
e.execute(request);
}
public static void main(String[] args) {
spawnThreads();
while (true) {
System.out.println(request.getOk());
if (!request.getOk())
request.setOk(true);
TimeUnit.SECONDS.sleep(10);
}
}
I need that if in the main thread, that getOk() returns false, do something and set it to true. Viceversa, set it to false in the thread (which I need to keep on going, no matter what the value of ok is at any given time).
As this code is, I can't get the value of request.getOk() in the main thread. If I remove the synchronized words from the getter and setter, I can access the value in the main thread until a point in time when it is changed by the thread, and never again.
Also, the executor is used because I would create multiple Request objects, and waiting for it to shutdown before accessing the variable would contradict my reason for doing this, as I would need all the threads to keep running.
That thread is making http requests to a server (that randomly times out, denies response, etc) and is used to retrieve some information. The ok variable is there to take a note when the thread acquires an ok response and some information from the server.
How do I solve it so that the thread can update that variable, but the main thread to be able to retrieve it whenever needed, no matter if it was changed by the thread in the meanwhile or not.
Would changing my Runnable to a Callable help? If yes, how?
Your example still leaves some holes in the thread-safety. Like mentioned by #Radiodef using AtomicBoolean can relieve you of most of the synchronisation if used properly.
Using your example, this is a thread safe Request class that accepts a message, like an answer to a http request.
public final class Request implements Runnable {
private final AtomicBoolean ok = new AtomicBoolean(false);
// volatile variables promote reference changes through all threads
private volatile String msg;
private boolean setMessage(String responseMessage) {
if (this.ok.compareAndSet(false, true)) {
this.msg = msg;
return true;
}
return false;
}
public boolean hasMessage() {
// *pure* getters don't need synchronisation!
return this.ok.get();
}
public String getMessageAndReset() {
// make a copy before resetting the OK
String msgCopy = this.msg;
this.ok.compareAndSet(true, false);
return msgCopy;
}
public void run() {
final Random rand = new Random();
try {
while(true) {
// sleep at random max 5 seconds
// (simulate unpredictable network)
TimeUnit.SECONDS.sleep(rand.nextInt(5));
while(!setMessage("Incoming message")) {
// busy waiting ... waits until the current value has
// been retrieved by the main thread
Thread.sleep(100);
}
}
} catch (Exception e) {
System.out.println(e);
}
}
}
And your main class:
public final class MainClazz implements Runnable {
private final ExecutorService exec;
private final Request request;
public void MainClazz() {
this.exec = new Executors.newFixedThreadPool(4);
this.request = new Request();
this.exec.execute(request);
}
public void run() {
while (true) {
if (request.hasMessage()) {
System.out.println(request.getMessageAndReset());
}
TimeUnit.SECONDS.sleep(10);
}
public static void main(String[] args) {
MainClazz main = new MainClazz();
main.run();
}
}
In this implementation, the Request class only holds a single value at a time. Depending the amount of data you expect you might want to think about using a buffer.
Also, like many others have mentioned, don't use while (true)! Get a synchronisation object from the java concurrent package!
More light reading on the AtomicBoolean object.

Adding to a message queue if more important messages come in

We need to send messages with highest priority first so we use a PriorityQueue for our purpose.
PriorityQueue<MessageData> queue = new PriorityQueue<MessageData>();
However, we also want our queue to behave like a sorted set as well. Therefore, we adapt the PriorityQueue to ignore insertions which repeat existing members.
import java.util.Comparator;
import java.util.PriorityQueue;
public class PrioritySet<E> extends PriorityQueue<E> {
private static final long serialVersionUID = 34658778L;
public PrioritySet() {
super();
}
public PrioritySet(int initialCapacity, Comparator<? super E> comparator) {
super(initialCapacity, comparator);
}
#Override
public boolean offer(E e) {
boolean isAdded = false;
if(!super.contains(e)) {
isAdded = super.offer(e);
}
return isAdded;
}
}
Now our app specific implementation of the data structure.
import java.util.Comparator;
public class MessagePrioritySet extends PrioritySet<MessageData> {
private static final long serialVersionUID = 34658779L;
private int minPriorityNumber;
public MessagePrioritySet() {
super();
}
public MessagePrioritySet(int initialCapacity, Comparator<MessageData> comparator) {
super(initialCapacity, comparator);
}
public synchronized int getMinPriorityNumber() {
return minPriorityNumber;
}
public synchronized void setMinPriorityNumber(int minPriorityNumber) {
this.minPriorityNumber = minPriorityNumber;
}
#Override
public synchronized boolean offer(MessageData notification) {
boolean isAdded = super.offer(notification);
if (notification.getPriority() < minPriorityNumber)
minPriorityNumber = notification.getPriority();
return isAdded;
}
public synchronized void reportSent(MessageData notification) {
MessageData nextMessageData = peek();
if (nextMessageData == null)
minPriorityNumber = 0;
else if (nextMessageData.getPriority() > notification.getPriority())
minPriorityNumber = nextMessageData.getPriority();
}
}
Here, we want the data structure to be aware of the minimum priority value of the messages so we declare an instance variable for that. The priority of the incoming message is checked and if this priority is lower than the stored value, the value stored is updated. The use of the class is required to report any sent messages. If no other member of the data structure has a priority as low as the one being removed, then the next element's priority becomes the stored priority.
Two threads share the implemented queue. One thread fetches data from the database and inserts them into the queue. The other reads the queue and sends the highest priority message with the lowest priority number. Because the queue sets the minimum priority value to 0 and the thread which fetches data from the database reads rows with priority value lower than or equal to the minimum value stored in the queue if the stored minimum value is not zero, we can be pretty sure that while the current messages in the queue are being sent, only the new messages which are more important than those already in the queue will be added to the queue.
We think that the operations in the while loops in the threads should be atomic and would thank anyone who could tell us how to make them atomic.
private void startMptSender() {
sleepInterval = 1000;
final MessagePrioritySet messagePrioritySet = new MessagePrioritySet();
Runnable mptReader = new Runnable() {
#Override
public void run() {
while (true) {
List<MessageData> messageDataList;
if (messagePrioritySet.getMinPriorityNumber() == 0)
messageDataList = messageDao.readSMSMpt();
else
messageDataList = messageDao.readSMSMpt(messagePrioritySet.getMinPriorityNumber());
for (MessageData messageData : messageDataList) {
messagePrioritySet.offer(messageData);
}
try {
Thread.sleep(sleepInterval);
} catch (InterruptedException ie) {
}
}
}
};
executor.execute(mptReader);
Runnable mptPusher = new Runnable() {
#Override
public void run() {
while (status) {
if (messagePrioritySet.size() > 0) {
while (messagePrioritySet.size() != 0) {
MessageData noti = messagePrioritySet.remove();
mptSender.sendSms(noti);
messageDao.markNotificationAsRead(noti.getSyskey());
messagePrioritySet.reportSent(noti);
try {
Thread.sleep(sleepInterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
try {
Thread.sleep(sleepInterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
executor.execute(mptPusher);
}
}
I assume what you mean with atomic translates to: you want that each thread is doing all of its work for one iteration without being interrupted by the other thread.
In other words: you have (probably multiple) operations; and while thread A is doing his operations, thread B shouldn't be doing anything - because you want to make sure that B only sees the "complete set" of updates made by A.
Sure, when that operation would be just about writing to one int for example, you could be using AtomicInteger for example. But when you are talking about several operations ... you need something else.
A "brute force" solution would be to add some sort of locking. Meaning: your threads share some LOCK object; and whenever one thread enters a "critical section" ... it needs to acquire that LOCK first (and of course release directly afterwards). But this will need very careful designing; as want to make sure that thread A isn't "starving" B by holding that lock for too long.
Looking at your code again, more closely ... maybe you could try to make your minPriority to be an AtomicInteger; the question is how that would relate to the other thread that is working the "size" of your queue.

DelayQueue with capacity

I'm using a DelayQueue. I need to use this so as to only take from the queue when a delay has passed. I also want to enforce a capacity, much like a BlockingQueue. I can't seem to find a Collections implementation of this. Does one exist? If not, what's the best way of implementing it? A basic approach would be to do something like this:
public void addSomethingToQueue(Object somethingToAdd){
int capacity = 4;
while(queue.size() >= capacity){
try{
wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
queue.add(somethingToAdd);
}
This would mean calling notify / notifyAll each time something was removed. It's quite a small class so that's doable. It doesn't sound great though. And I'm not sure if the wait / notify may cause further problems?
Would it be better to sub-class DelayQueue and mess around with its methods? It feels a bit dodgy...
Why not compose a BlockingQueue and a DelayQueue? For e.g.:
class MyDelayBlockingQueue<T> implements Queue {
private final DelayQueue<T> delayQ = ...
private final BlockingQueue<T> blockingQ = ...
public synchronized void offer(T obj) {
blockingQ.offer(obj); // this will block if the Q is full
delayQ.offer(obj);
}
public synchronized T poll() {
T obj = delayQ.poll(); // This will handle the delay
if (obj != null) {
blockingQ.poll();
}
return obj;
}
// ...
}
EDIT
The code above will deadlock. If the Q is full, offer will block in a synchronized block, and all future calls to poll will block to acquire the intrinsic lock of the Q - causing a deadlock. Try something like instead:
public class DelayBlockingQueue<E extends Delayed>
{
private final DelayQueue<E> delayQ = new DelayQueue<E>();
private final Semaphore available;
public DelayBlockingQueue(int capacity)
{
available = new Semaphore(capacity, true);
}
public void offer(E e) throws InterruptedException
{
available.acquire();
delayQ.offer(e);
}
public E poll()
{
E e = delayQ.poll();
if (e != null)
{
available.release();
}
return e;
}
}
You may using LRU:
http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
Example implementation from Apache Commons:
http://commons.apache.org/collections/api/org/apache/commons/collections/LRUMap.html
So you don't write this again ;-)

Categories

Resources