I have two processes (producer/consumer). The first one puts elements in a Collection, the second one reads them.
I want the second process not to read every individual element, but wait until:
There are at least N elements in the collection OR
The last element was received T seconds ago.
Is there any Collection in Java 5+ that allows this kind of behaviour? I was thinking about an implementation of Queue, but I've only found DelayQueue that is not exactly what I need.
Thank you.
I'd implement an observable collection. The second process will listen to events, signalling that N elements are in the collection (events based on size attribute) and that no element has been added for a certain time (needs a timer, that is reset on every add operation)
Something like this (just drafting the size requirement):
public ObservableCollection implements Collection {
private int sizetrigger;
private Collection collection;
private Collection<Listener> listeners = new ArrayList<Listener>();
public ObservableCollection(Collection collection) {
this.collection = collection;
}
#Override
boolean add(Object element) {
collection.add(element);
if (size >= sizeTrigger) {
fireSizeEvent();
}
}
private fireSizeEvent() {
for(Listener listener:listeners) {
listener.thresholdReached(this);
}
}
// addListener, removeListener and implementations of interface methods
}
Related
I have currently two queues and items traveling between them. Initially, an item gets put into firstQueue, then one of three dedicated thread moves it to secondQueue and finally another dedicated thread removes it. These moves obviously include some processing. I need to be able to get the status of any item (IN_FIRST, AFTER_FIRST, IN_SECOND, AFTER_SECOND, or ABSENT) and I implemented it manually by doing the update of the statusMap where the queue gets modified like
while (true) {
Item i = firstQueue.take();
statusMap.put(i, AFTER_FIRST);
process(i);
secondQueue.add(i);
statusMap.put(i, IN_SECOND);
}
This works, but it's ugly and leaves a time window where the status is inconsistent. The inconsistency is no big deal and it'd solvable by synchronization, but this could backfire as the queue is of limited capacity and may block. The ugliness bothers me more.
Efficiency hardly matters as the processing takes seconds. Dedicated threads are used in order to control concurrency. No item should ever be in multiple states (but this is not very important and not guaranteed by my current racy approach). There'll be more queues (and states) and they'll of different kinds (DelayQueue, ArrayBlockingQueue, and maybe PriorityQueue).
I wonder if there's a nice solution generalizable to multiple queues?
Does it make sense to wrap the queues with logic to manage the Item status?
public class QueueWrapper<E> implements BlockingQueue<E> {
private Queue<E> myQueue = new LinkedBlockingQueue<>();
private Map<E, Status> statusMap;
public QueueWrapper(Map<E, Status> statusMap) {
this.statusMap = statusMap;
}
[...]
#Override
public E take() throws InterruptedException {
E result = myQueue.take();
statusMap.put(result, Status.AFTER_FIRST);
return result;
}
That way status management is always related to (and contained in) queue operations...
Obviously statusMap needs to be synchronized, but that would be an issue anyway.
I see that your model might be improved in consistency, state control, and scaling.
A way of to implement this is accouple the item to your state, enqueue and dequeue this couple and create a mechanism to ensure state change.
My proposal can be see in figure below:
According with this model and your example, we can to do:
package stackoverflow;
import java.util.concurrent.LinkedBlockingQueue;
import stackoverflow.item.ItemState;
import stackoverflow.task.CreatingTask;
import stackoverflow.task.FirstMovingTask;
import stackoverflow.task.SecondMovingTask;
public class Main {
private static void startTask(String name, Runnable r){
Thread t = new Thread(r, name);
t.start();
}
public static void main(String[] args) {
//create queues
LinkedBlockingQueue<ItemState> firstQueue = new LinkedBlockingQueue<ItemState>();
LinkedBlockingQueue<ItemState> secondQueue = new LinkedBlockingQueue<ItemState>();
//start three threads
startTask("Thread#1", new CreatingTask(firstQueue));
startTask("Thread#2", new FirstMovingTask(firstQueue, secondQueue));
startTask("Thread#3", new SecondMovingTask(secondQueue));
}
}
Each task runs the operations op() of according with below affirmation on ItemState:
one of three dedicated thread moves it to secondQueue and finally
another dedicated thread removes it.
ItemState is a immutable object that contains Item and your State. This ensures consistency between Item and State values.
ItemState has acknowledgement about the next state creating a mechanism of self-controled state:
public class FirstMovingTask {
//others codes
protected void op() {
try {
//dequeue
ItemState is0 = new ItemState(firstQueue.take());
System.out.println("Item " + is0.getItem().getValue() + ": " + is0.getState().getValue());
//process here
//enqueue
ItemState is1 = new ItemState(is0);
secondQueue.add(is1);
System.out.println("Item " + is1.getItem().getValue() + ": " + is1.getState().getValue());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//others codes
}
With ItemState implemetation:
public class ItemStateImpl implements ItemState {
private final Item item;
private final State state;
public ItemStateImpl(Item i){
this.item = i;
this.state = new State();
}
public ItemStateImpl(ItemState is) {
this.item = is.getItem();
this.state = is.getState().next();
}
// gets attrs
}
So this way is possible build solutions more elegant, flexible and scalable.
Scalable because you can to control more states only changing next() and generalizing the moving task for increase the number of queue.
Results:
Item 0: AFTER_FIRST
Item 0: IN_FIRST
Item 0: IN_SECOND
Item 0: AFTER_SECOND
Item 1: IN_FIRST
Item 1: AFTER_FIRST
Item 1: IN_SECOND
Item 1: AFTER_SECOND
Item 2: IN_FIRST
Item 2: AFTER_FIRST
Item 2: IN_SECOND
... others
UPDATE(06/07/2018): analysing the use of map for search
Search in map using equals values like comparator might not work because usally the mapping between values and identity (key/hash) is not one-to-one(see figure bellow). In this way is need to create an sorted list for search values which results in O(n) (worst-case).
with Item.getValuesHashCode():
private int getValuesHashCode(){
return new HashCodeBuilder().append(value).hashCode();
}
In this case, you must keep Vector<ItemState> instead of Item and to use the key like the result of getValuesHashCode. Change the mechanism of state-control for keep first reference of the Item and the state current. See bellow:
//Main.class
public static void main(String[] args) {
... others code ...
//references repository
ConcurrentHashMap<Integer, Vector<ItemState>> statesMap = new ConcurrentHashMap<Integer, Vector<ItemState>>();
//start three threads
startTask("Thread#1", new CreatingTask(firstQueue, statesMap));
... others code ...
}
//CreateTask.class
protected void op() throws InterruptedException {
//create item
ItemState is = new ItemStateImpl(new Item(i++, NameGenerator.name()));
//put in monitor and enqueue
int key = is.getHashValue();
Vector<ItemState> items = map.get(key);
if (items == null){
items = new Vector<>();
map.put(key, items);
}
items.add(is);
//enqueue
queue.put(is);
}
//FirstMovingTask.class
protected void op() throws InterruptedException{
//dequeue
ItemState is0 = firstQueue.take();
//process
ItemState is1 = process(is0.next());
//enqueue
secondQueue.put(is1.next());
}
//ItemState.class
public ItemState next() {
//required for consistent change state
synchronized (state) {
state = state.next();
return this;
}
}
To search you must use concurrentMapRef.get(key). The result will the reference of updated ItemState.
Results in my tests for :
# key = hash("a")
# concurrentMapRef.get(key)
...
Item#7#0 : a - IN_FIRST
... many others lines
Item#7#0 : a - AFTER_FIRST
Item#12#1 : a - IN_FIRST
... many others lines
Item#7#0 : a - IN_SECOND
Item#12#1 : a - IN_FIRST
... many others lines
Item#7#0 : a - AFTER_SECOND
Item#12#1 : a - IN_FIRST
More details in code: https://github.com/ag-studies/stackoverflow-queue
UPDATED IN 06/09/2018: redesign
Generalizing this project, I can undestand that the state machine is something like:
In this way I decoupled the workers of the queues for improve concepts. I used an MemoryRep for keep the unique reference for item in overall processment.
Of course that you can use strategies event-based if you need keep ItemState in a physic repository.
This keep the previous idea and creates more legibility for the concepts. See this:
I understand that each job will have two queue (input/output) and relationship with a business model! The researcher will always find the most updated and consistent state of Item.
So, answering your ask:
I can find the consistent state of Item anywhere using MemoryRep (basically an Map), wrapping state and item in ItemState, and controlling the change state on job on enqueue or dequeue it.
The performace is keeped, except on running of next()
The state is allways consistent (for your problem)
In this model is possible use any queue type, any number of jobs/queues, and any number of state.
Additionaly this is beautiful!!
As previously answered, Wrap the queues or the item would be viable solutions or both.
public class ItemWrapper<E> {
E item;
Status status;
public ItemWrapper(Item i, Status s){ ... }
public setStatus(Status s){ ... }
// not necessary if you use a queue wrapper (see queue wrapper)
public boolean equals(Object obj) {
if ( obj instanceof ItemWrapper)
return item.equals(((ItemWrapper) obj).item)
return false;
}
public int hashCode(){
return item;
}
}
...
process(item) // process update status in the item
...
Probably a better way, already answered, is to have a QueueWrapper who update the queue status. For the fun I don't use a status map but I use the previously itemwrapper it seems cleaner (a status map works too).
public class QueueWrapper<E> implements Queue<E> {
private Queue<ItemWrapper<E>> myQueue;
static private Status inStatus; // FIRST
static private Status outStatus; // AFTER_FIRST
public QueueWrapper(Queue<E> myQueue, Status inStatus, Status outStatus) {...}
#Override
public boolean add(E e) {
return myQueue.add(new ItemWrapper(e, inStatus));
}
#Override
public E remove(){
ItemWrapper<E> result = myQueue.remove();
result.setStatus(outStatus)
return result.item;
}
...
}
You can also use AOP to inject status update in your queues without changing your queues (a status map should be more appropriate than itemwrapper).
Maybe I didn't answer well your question because an easy way to know where is your item could be to check in each queue with "contains" function.
Here's something different from what others have said. Taking from the world of queue services and systems we have the concept of message acknowledgement. This is nice, because it also gives you some built in retry logic.
I'll lay out how it would work from a high level, and if you need I can add code.
Essentially you'll have a Set to go with each of your queues. You'll wrap your queues in an object so that when you dequeue an item a few things happen
The item is removed from the queue
The item is added to the associated set
A task (lambda containing an atomic boolean (default false)) is scheduled. When run it will remove item from the set and if the boolean is false, put it back in the queue
The item and a wrapper around the boolean are returned to the caller
Once process(i); completes, your code will indicate receipt acknowledgement to the wrapper, and the wrapper will remove the item from the set and make the boolean false.
A method to return status would simply check which queue or set the item is in.
Note that this gives "at least once" delivery, meaning an item will be processed at least once, but potentially more than once if the processing time is too close to the timeout.
I'm using
Collections.synchronizedList(new ArrayList<T>())
part of the code is:
list = Collections.synchronizedList(new ArrayList<T>());
public void add(T arg) {
int i;
synchronized (list) {
for (i = 0; i < list.size(); i++) {
T arg2 = list.get(i);
if (arg2.compareTo(arg) < 0) {
list.add(i, arg);
break;
}
}
Is it right that for loop is actually using iterator and therefore I must wrap the for with synchronized?
Is it thread-safe to use synchronized and make addition inside it like I did here?
I'm sorry if these questions are very basic, I'm new to the subject and didn't find answers on the internet.
Thank you!!
Is it right that for loop is actually using iterator and therefore I must wrap the for with synchronized?
There are two parts to your question.
Firstly, no, you're not using an iterator here, this is a basic for loop.
The enhanced for loop is the for loop which uses an iterator:
for (T element : list) { ... }
You can see in the language spec how this uses the iterator - search for where it says "The enhanced for statement is equivalent to a basic for statement of the form".
Secondly, even though you're not using an iterator, you do need synchronized. The two are orthogonal.
You are doing multiple operations (the size, the get and the add), with dependencies between them. You need to make sure that no other thread interferes with your logic:
the get depends on the size, since you don't want to try to get an element with index >= size, for instance;
the add depends on the get, since you're apparently trying to ensure the list elements are ordered. If another thread could sneak in and change the element after you get it, you might insert the new element in the wrong place.
You correctly avoid this potential interference this through synchronization over list, and creating the synchronizedList in such a way that nothing other than the synchronizedList can get direct access to the underlying list.
If your arg2.compareTo(arg) never return 0 (zero) you can use TreeSet. Will be much more simple:
set = Collections.synchronizedSet(new TreeSet<T>());
public void add(T arg) {
set.add(arg);
}
If you need hold same items (compareTo returns 0) then use the list:
list = new ArrayList<T>();
public void add(T arg) {
synchronized (list) {
int index = Collections.binarySearch(list, arg);
list.add(index, arg);
}
}
First and second cases complexity will be log(N) (10 for 1000 items). Your code complexity is N (1000 for 1000 items).
The idea of LinkedList is, that each element has a reference to its successor (and predecessor in the case of doubled linked list), so concatenation of two LinkedLists happens that last element of the first list get reference to first element of second list Detailed explanation here, what is made in O(1) time.
Howewer they made it stupid in Java.
It has no method java.util.LinkedList.addFirst(LinkedList) or something.
if you look at the method java.util.LinkedList.addAll(Collection), it iterates over an array, what collection returns with c.toArray(), and then adds each element of this array. What is even twice stupid:
1) linked list is iterated in 0(n)
2) elements are added to linked list in 0(n) time.
Is there any possibility to extends the standart LinkedList so he would have good concatenation method? Because now, the simplest, but bad solution i see to make the copy- paste of LinkedList code and make some methods protected in order to extend that with implementation of right addALL
You can't use addAll for that, because O(1) linked list concatenation is a destructive operation. In other words, you start with two non-empty lists, and end up with one big list and one empty list.
You are looking for two operations
void transferBeforeFirst(LinkedList<T> other);
void transferAfterLast(LinkedList<T> other);
They take LinkedList<T> other in whatever state it may be, and leave it empty upon return. This is rather counterintuitive, because generally the caller expects to find his data unchanged after calling a library method.
Of course, technically this could certainly be done. However, this goes against the grain of Java API design, which prefers to leave method parameters unchanged.
I don't think there is a way to do that, and the reason is that java has a strong object orientation and doesn't operate with data in a direct way such has C does, so if you have two linked lists and you want to make one out of two, you are forced to copy one of them entirely instead of only liking it at the end of the other one.
This behaviour is because special casing the adding of two linked lists together would destroy the sconfd list.
Notice that the LinkedList.Node class has both a next and a prev so it is indeed doubly-linked. To just join the chains together would make list2.first.prev point to list1.last which would then break list2.
public void addLast(LinkedList<? extends E> l) {
// My list continues on into the new list.
last.next = l.first;
// Back-link too - THIS BREAKS l!!
l.first.prev = last;
// End of new list is now last.
last = l.last;
}
Secondly notice that LinkedList<? extends E>. Remember that you can extend LinkedList so you may be adding two lists of a completely different class together - that would also require careful handling.
If you really want to achieve O(1) you could write an IterableIterable that would walk an Itearble<Iterable<T>> delivering each element from each Iterable in turn - kind of like a flatMap for Iterables.
class IterableIterable<T> implements Iterable<T> {
private final Iterable<? extends Iterable<T>> i;
public IterableIterable(Iterable<? extends Iterable<T>> i) {
this.i = i;
}
#Override
public Iterator<T> iterator() {
return new IIT();
}
private class IIT implements Iterator<T> {
// Pull an iterator.
final Iterator<? extends Iterable<T>> iit = i.iterator();
// The current Iterator<T>
Iterator<T> it = null;
// The current T.
T next = null;
#Override
public boolean hasNext() {
boolean finished = false;
while (next == null && !finished) {
if (it == null || !it.hasNext()) {
if (iit.hasNext()) {
it = iit.next().iterator();
} else {
// All over when we've exhausted the list of lists.
finished = true;
}
}
if (it != null && it.hasNext()) {
// Get another from the current list.
next = it.next();
}
}
return next != null;
}
#Override
public T next() {
T n = next;
next = null;
return n;
}
}
}
That's why LinkedList has the addLast() method
https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#addLast%28E%29
and it does have a addFirst() too
https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#addFirst%28E%29
you can't do better than that, because Java has not the pointer concept.
you could try to implement your own native code for that, however.
I am using ConcurrentSkipListSet, which I fill with 20 keys.
I want to replace these keys continuously. However, ConcurrentSkipListSet doesn't seem to have an atomic replace function.
This is what I am using now:
ConcurrentSkipListSet<Long> set = new ConcurrentSkipListSet<Long>();
AtomicLong uniquefier = new AtomicLong(1);
public void fillSet() {
// fills set with 20 unique keys;
}
public void updateSet() {
Long now = Calendar.getInstance().getTimeInMillis();
Long oldestKey = set.first();
if (set.remove(oldestKey)) {
set.add(makeUnique(now));
}
}
private static final long MULTIPLIER = 1024;
public Long makeUnique(long in) {
return (in*MULTIPLIER+uniquefier.getAndSet((uniquefier.incrementAndGet())%(MULTIPLIER/2)));
}
The goal of this whole operation is to keep the list as long as it is, and only update by replacing. updateSet is called some 100 times per ms.
Now, my question is this: does remove return true if the element itself was present before (and isn't after), or does the method return true only if the call was actually responsible for the removal?
I.e.: if multiple threads call remove on the very same key at the very same time, will they /all/ return true, or will only one return true?
set.remove will only return true for the thread that actually caused the object to be removed.
The idea behind the set's concurrency is that multiple threads can be updating multiple objects. However, each individual object can only be updated by one thread at a time.
My problem
Let's say I want to hold my messages in some sort of datastructure for longpolling application:
1. "dude"
2. "where"
3. "is"
4. "my"
5. "car"
Asking for messages from index[4,5] should return:
"my","car".
Next let's assume that after a while I would like to purge old messages because they aren't useful anymore and I want to save memory. Let's say after time x messages[1-3] became stale. I assume that it would be most efficient to just do the deletion once every x seconds. Next my datastructure should contain:
4. "my"
5. "car"
My solution?
I was thinking of using a concurrentskiplistset or concurrentskiplist map. Also I was thinking of deleting the old messages from inside a newSingleThreadScheduledExecutor. I would like to know how you would implement(efficiently/thread-safe) this or maybe use a library?
The big concern, as I gather it, is how to let certain elements expire after a period. I had a similar requirement and I created a message class that implemented the Delayed Interface. This class held everything I needed for a message and (through the Delayed interface) told me when it has expired.
I used instances of this object within a concurrent collection, you could use a ConcurrentMap because it will allow you to key those objects with an integer key.
I reaped the collection once every so often, removing items whose delay has passed. We test for expiration by using the getDelay method of the Delayed interface:
message.getDelay(TimeUnit.MILLISECONDS);
I used a normal thread that would sleep for a period then reap the expired items. In my requirements it wasn't important that the items be removed as soon as their delay had expired. It seems that you have a similar flexibility.
If you needed to remove items as soon as their delay expired, then instead of sleeping a set period in your reaping thread, you would sleep for the delay of the message that will expire first.
Here's my delayed message class:
class DelayedMessage implements Delayed {
long endOfDelay;
Date requestTime;
String message;
public DelayedMessage(String m, int delay) {
requestTime = new Date();
endOfDelay = System.currentTimeMillis()
+ delay;
this.message = m;
}
public long getDelay(TimeUnit unit) {
long delay = unit.convert(
endOfDelay - System.currentTimeMillis(),
TimeUnit.MILLISECONDS);
return delay;
}
public int compareTo(Delayed o) {
DelayedMessage that = (DelayedMessage) o;
if (this.endOfDelay < that.endOfDelay) {
return -1;
}
if (this.endOfDelay > that.endOfDelay) {
return 1;
}
return this.requestTime.compareTo(that.requestTime);
}
#Override
public String toString() {
return message;
}
}
I'm not sure if this is what you want, but it looks like you need a NavigableMap<K,V> to me.
import java.util.*;
public class NaviMap {
public static void main(String[] args) {
NavigableMap<Integer,String> nmap = new TreeMap<Integer,String>();
nmap.put(1, "dude");
nmap.put(2, "where");
nmap.put(3, "is");
nmap.put(4, "my");
nmap.put(5, "car");
System.out.println(nmap);
// prints "{1=dude, 2=where, 3=is, 4=my, 5=car}"
System.out.println(nmap.subMap(4, true, 5, true).values());
// prints "[my, car]" ^inclusive^
nmap.subMap(1, true, 3, true).clear();
System.out.println(nmap);
// prints "{4=my, 5=car}"
// wrap into synchronized SortedMap
SortedMap<Integer,String> ssmap =Collections.synchronizedSortedMap(nmap);
System.out.println(ssmap.subMap(4, 5));
// prints "{4=my}" ^exclusive upper bound!
System.out.println(ssmap.subMap(4, 5+1));
// prints "{4=my, 5=car}" ^ugly but "works"
}
}
Now, unfortunately there's no easy way to get a synchronized version of a NavigableMap<K,V>, but a SortedMap does have a subMap, but only one overload where the upper bound is strictly exclusive.
API links
SortedMap.subMap
NavigableMap.subMap
Collections.synchronizedSortedMap