Synchronize ArrayList in or outside of while loop? - java

So i have a pretty simple case:
while (resultSet.next())
{
list.add(...);
}
I want to synchronize the list. (synchronized (list))
Now is it better to synchronize the complete while loop? Or should the synchronized block be inside the while loop?
Is there, depending on performance, a relevant difference when he has to lock and release the list on every single loop?

It would be better to add the entries to a new list that no other thread is accessing, then add them all together ( using addAll) to the shared ArrayList once you're done reading from the resultSet. That way you would have to synchronize only once, it would minimize contention with other threads, and you wouldn't be holding the lock while doing I/O.
List localList = new ArrayList();
while (resultSet.next()) {
localList.add(resultSet.get...);
}
synchronized(list) {
list.addAll(localList);
}

The main difference would be that if you lock outside the loop, then other sync operations on the list from other threads will have to wait for the whole loop to finish.
If you just sync inside the loop, other threads can modify the list between inserts.
So the right thing to do would depend on the behaviour you are looking for.
Also, please note that you need to sync on the list in all other places in order for that to work properly. If other threads modify the list without trying to get the lock, they will be able to do so.
To prevent that, you could use a collection that already provides thread safety.
Or you can create the list like this, and not worry about having to synchronize yourself:
List aList = Collections.synchronizedList(new ArrayList());

Ideal scenario, you should synchronize only the specific block of code, rather than the entire loop. One can have a seperate synchronized method which could be invoked from the while loop. this allows other thread to continue their execution. if you are not carrying-out any expensive operation (like DB updation), try to seek alternatives as Synchronized blocks affect performance thus its always advisable to use it carefully.

Related

Preserving order of add operation encounter Concurrent list/queue insertion

I have multithreaded code where each thread needs to write to a shared list/queue. I want to ensure that multiple add operations can proceed concurrently and that the order in which each thread encounters the add operation is preserved. I do not want to synchronize the add operation if at all possible.
In the above image, green represents the thread that first encountered the add operation, blue represents the thread that encountered it second and red represents the thread that encountered it third. Even if red thread completed insertion before blue thread, I want the order to be effected as depicted.
I'm wondering if there are any existent suitable structures in the java concurrent package (LinkedBlockingQueue perhaps?) and if not, whether someone can offer any tips about what I would need to do in defining my own structure which could fulfill the requirements above.
My best guess at this point is to add a volatile int variable to the multithreaded code that increments immediately before the add operation, which is sent with the Thread.currentThread.getId() value, and can then be used after all write operations are completed, to sort the list/queue structure so that the elements are ordered according to the int variable's value at each element.
Any advice would be appreciated.
EDIT:
It should be noted explicitly that insert operations need to take place in constant time.
Your best bet would be to use ConcurrentHashMap and AtomicInteger as counter.
So every thread right before adding his ID to map calls the
int id= AtomicInteger.getAndIncrement();
and the you put into ConcurrentHashMap<Integer, Integer> map
map.put(id, threadId);
then after the work is done you can sort entrySet by the key and you get the rigth order
alternatively you can use ConcurrentSkipListMap which will sort by the natural ordering of the keys, or by specified comparator.
But, i think that there is some part of the story that you still need to discover yourself, hard to say what it is now, just the picture you painted has some context and it seems like this context still hides something that you will discover. Just the problem you described comes from somwhere else, and it feel like the solution to it should be differnet than this kind of ordering.
LinkedBlockingQueue uses synchronization internally, in the form of ReentrantLock -- that's how it implements the 'blocking' part.
Something like this should work:
AtomicBoolean busy = new AtomicBoolean(false);
Thread t = new Thread(() -> {
while (!busy.compareAndSet(false, true)) {
// busy wait
}
try {
list.add(Thread.currentThread().getId());
} finally {
busy.set(false);
}
};
Here threads compete at the busy flag. One of them wins the right to add to the list, others busy-wait until the winning thread clears the flag.
The two calls to AtomicBoolean methods establish proper 'happens-before' relationship between list.add() calls done on different threads, so each thread should observe actual state of the list.
LinkedList can be used for unbounded queues. For bounded ones, maybe ArrayList with initial capacity set.
When calls are concurrent, by their nature, they are not ordered (that is what the word concurrent implies).
Ordering of requests based on the physical arrival time makes no sense; I do not know of any concurrency model that has such a requirement.
The simplest solution would be to use a synchronized wrapper around an AtomicList and add the threads to that list.
If you really want to go for a 'non blocking' data-structure, I would have a look at a concurrent ringbuffer like those from JCTools. But before going for such a solution, I would first benchmark your code and figure out where your bottleneck is before just adding random complexity.

Sync block required for Collections.synchronizedList.add()?

My understanding of this is that a synchronized block keeps other threads from accessing until such time as that block terminates; that is, they are put on hold till then via a lock held by the currently executing class (?).
So I wrap a for block which iterates over a list and then calls clear() on that list directly thereafter, in a synchronized block. as I can't afford to have other threads adding to the list between those two sets of operations. This is in accordance with the docs, which say,
It is imperative that the user manually synchronize on the returned
collection when iterating over it...
However I can't figure for sure whether I need to do the same when I am adding to the list. I am guessing not, since in my case the order of add operations from different threads is not important. I guess that what I'm unsure of is whether unsynchronized modify operations might have any negative impacts?
You only need locking when you have multiple operations which must work together. In the case of an Iterator, you will perform any operations over the life of the loop.
If adds can occur in any order, no additional locking is required.
I wrap a for block which iterates over a list and then calls clear()
From your use case, it sounds like a BlockingQueue (is thread safe without synchronized) or even an ExecutorService (which combines a thread pool with a queue) would be a better choice.
It is important that you synchronize on Collection itself
Collection c = Collections.synchronizedCollection(myCollection);
...
synchronized (c) {
for(Object o : c) {
....
}
other threads calling any methods of c will be blocked until you leave the block. No other synchronization is necessary

Synchronizing threads to avoid ArrayIndexOutOfBoundsException

I have two seperate threads:
logicThread - for ai, movement, sprite sorting and destruction of sprites
drawingThread - for drawing (canvas.draw())
My logic thread calls ArrayList.remove(), so I would think when the drawing thread comes to draw there could be a chance of crashing because the index no longer exists.
code sample:
drawingThread extends Thread {
logicThread = new LogicThread;
logicThread.start();
public void run(){
while(running) {
for(int i=0; i<npc.size(); i++){
npc.get(i).callDraw();
}
}
// stop logicThread when out of gameloop
logicThread.running = false;
}}
LogicThread extends Thread {
public void run(){
while(running){
for(int i=0; i<npc.size();i++){
if(npc.get(i).isDead()){
npc.remove(i);
}
npc.trimToSize();
}
Collection.sort(npc);
}
}}
Which would be the correct way to prevent an exception, syncronized or trycatch?
Also are there any benefits from using one over the other?
synchronized(logicThread) {
for(int i=0; npc.size(); i++) {
npc.callDraw();
}}
or
try {
npc.callDraw();
} catch(Exception e) {}
Just for note: use iterators to remove items from collection:
while (it.hasNex()) {
if(...) {
it.remove();
Catching IndexOutOfBound exception is valid if it's acceptable. Another way - is to create array copy in drawing thread, which will guarantee that you don't get IndexOutOfBound. You can just add a check isDead() inside drawing loop
You should not catch an ArrayIndexOutOfBoundsException, as this is an unchecked exception, this should be used for programming errors and only be thrown when one has occurred (note that this is a little bit controversial, but the above is what Effective Java, Bloch tells us).
If the action you are taking takes little time, use synchronization. If the loop takes a lot of time, use synchronization to copy the list and then iterate over the copy instead of the original.
Another problem you might run into (depending on the type of list you are using), is the ConcurrentModificationException, which occurs when you remove an element from a list that is being iterated.
Also note that if you do not synchronize shared objects when using it in the two threads, that you can have weird memory effects (such as seeing incomplete objects). Java Concurrency in practice by Goetz is a great book that teaches more on this widely misunderstood concept.
An alternative solution to using a synchronized block is using a CopyOnWriteArrayList, which will prevent the ConcurrentModificationException and the memory effects. Note that in order to use the 'copy effect' you need to use the iterators to the remove the elements.
You should absolutely synchronize access, but you need to do it in both threads, and you need to synchronize on the shared objects, e.g.
synchronized(npc) {
// Do something that accesses or modifies npc
}
Looking at your specific example, I would suggest that you probably don't want do it this way since you will need to hold a lock around the for loop. You probably need to move the synchronization into the shared npc object.
Is there any reason you can't just note in the first thread which npcs have died, and then remove them from your list once you exit the for loop. It's much better to avoid a separate thread and the synchronization if you can.
Do you need threads for this? If you call the drawing loop followed by the logic loop (serially) do you get an adequate frame rate? Assuming you have a double buffered display. Threads should usually be used where there is something asynchronous going on (like waiting for a server to respond) which you can't control. In this case you have control of when and in which order things happen.
Synchronizing over the entire draw / logic blocks will negate the benefits of threading, and catching the exception could lead to inconsistent UI (not to mention harder to manage code).
When iterating over a collection that another thread might modify, copy it first!
List drawList = new ArrayList(npc);
for(int i=0; i<drawList.size(); i++){
drawList.get(i).callDraw();
}
You probably still need to synchronize the copy operation; the risks are far lower but there's still a race condition that will lead to nulls in your copy. Collections.synchronizedList() can turn a regular list into a synchronized list but at the expense of some speed on all operations.
If performance with synchronizedList() becomes a problem you can just manually synchronize the copy and remove operations.

Returning Java Arrays vs Collections

I'm trying to think through some design in regards to memory allocation and multithreading in a java app and this is what I'm wondering:
I have a class that has a synchronized Collection say a list that is getting updated several times a a second but all updates are happening within the class and its own thread not from other threads. However I have many other threads that call the getCollection() method and do a foreach to iterate its contents in a read only fashion. This is what I don't know:
If another thread is iterating the synchronized colletion will the single thread that performs the updates have to wait until a point in time when no other threads are iterating?
My second question is it seems to make sense to return an array copy of the collection not the collection itself by doing .toArray but from thinking about it from a memory point of view won't that have to allocate a new array that is the size of the collection contents everytime and if getting called hundreds of times a second on a collection that has several thousand objects in it is something I don't know makes sense or not.
Also if I never return the collection itself than making the list synchronized is no longer necessary?
Would appreciate any input. Thanks! - Duncan
if another thread is iterating the
synchronized colletion will the single
thread that performs the updates have
to wait until a point in time when no
other threads are iterating?
If you're talking about synchronized (not concurrent) collections then yes.
As for the second question, it
looks like a real use case for java.util.concurrent.CopyOnWriteArrayList.
I would suggest you use the CopyOnWriteArrayList. This is thread safe and can be read accessed efficient by any number of threads. Provided you have a small number of updates this should be fine.
However, to answer your questions. If you iterator over a synchronized collection while it is being modifed, you will get a ConcurrentModificationException (COWAL doesn't get this) Your update will not be blocked by this, only your readers will have a problem.
Instead of creating a copy each time getCollection is called, youc an create a copy each time the collection is modifed (far less often) This is what COWAL does for you.
If you return a copy on demand, you will still need to synchronize the collection.
Probably the easiest way to deal with this is to keep two collections: one that is updated by the class itself, and a read-only copy in a volatile field that is returned when getCollection() is called.
The latter needs to be recreated by the process that updates the main collection when appropiate. This allows you to atomically update your collection: change several elements in one go, while hiding the intermediate states.
If your updates are infrequent and every update leaves the collection in a consistent state, then use the CopyOnWriteArrayList already suggested.
It seems that the collections is being updated frequently and #getCollection() is being called frequently. You could use CopyOnWriteArrayList but you'll creating a copy every time you modify the array. So you'll need to see how this effects performance.
Another option is to task the thread within the class to make a copy everytime #getCollection is called. This will involve #getCollection waiting for the internal class thread to complete.
If you just want #getCollection to return a recent copy and not the most up to date copy then you can have the internal thread periodically create a copy of the collection that gets returned in #getCollection. The copy will need to be volatile or be an AtomicReference.

How to use ConcurrentLinkedQueue?

How do I use a ConcurrentLinkedQueue in Java?
Using this LinkedQueue, do I need to be worried about concurrency in the queue? Or do I just have to define two methods (one to retrive elements from the list and another to add elements to the list)?
Note: obviously these two methods have to be synchronized. Right?
EDIT: What I'm trying to do is this: I have a class (in Java) with one method to retrieve items from the queue and another class with one method to add items to the queue. The items added and retrieved from the list are objects of my own class.
One more question: do I need to do this in the remove method:
while (queue.size() == 0){
wait();
queue.poll();
}
I only have one consumer and one producer.
No, the methods don't need to be synchronized, and you don't need to define any methods; they are already in ConcurrentLinkedQueue, just use them. ConcurrentLinkedQueue does all the locking and other operations you need internally; your producer(s) adds data into the queue, and your consumers poll for it.
First, create your queue:
Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>();
Now, wherever you are creating your producer/consumer objects, pass in the queue so they have somewhere to put their objects (you could use a setter for this, instead, but I prefer to do this kind of thing in a constructor):
YourProducer producer = new YourProducer(queue);
and:
YourConsumer consumer = new YourConsumer(queue);
and add stuff to it in your producer:
queue.offer(myObject);
and take stuff out in your consumer (if the queue is empty, poll() will return null, so check it):
YourObject myObject = queue.poll();
For more info see the Javadoc
EDIT:
If you need to block waiting for the queue to not be empty, you probably want to use a LinkedBlockingQueue, and use the take() method. However, LinkedBlockingQueue has a maximum capacity (defaults to Integer.MAX_VALUE, which is over two billion) and thus may or may not be appropriate depending on your circumstances.
If you only have one thread putting stuff into the queue, and another thread taking stuff out of the queue, ConcurrentLinkedQueue is probably overkill. It's more for when you may have hundreds or even thousands of threads accessing the queue at the same time. Your needs will probably be met by using:
Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());
A plus of this is that it locks on the instance (queue), so you can synchronize on queue to ensure atomicity of composite operations (as explained by Jared). You CANNOT do this with a ConcurrentLinkedQueue, as all operations are done WITHOUT locking on the instance (using java.util.concurrent.atomic variables). You will NOT need to do this if you want to block while the queue is empty, because poll() will simply return null while the queue is empty, and poll() is atomic. Check to see if poll() returns null. If it does, wait(), then try again. No need to lock.
Finally:
Honestly, I'd just use a LinkedBlockingQueue. It is still overkill for your application, but odds are it will work fine. If it isn't performant enough (PROFILE!), you can always try something else, and it means you don't have to deal with ANY synchronized stuff:
BlockingQueue<YourObject> queue = new LinkedBlockingQueue<YourObject>();
queue.put(myObject); // Blocks until queue isn't full.
YourObject myObject = queue.take(); // Blocks until queue isn't empty.
Everything else is the same. Put probably won't block, because you aren't likely to put two billion objects into the queue.
This is largely a duplicate of another question.
Here's the section of that answer that is relevant to this question:
Do I need to do my own synchronization if I use java.util.ConcurrentLinkedQueue?
Atomic operations on the concurrent collections are synchronized for you. In other words, each individual call to the queue is guaranteed thread-safe without any action on your part. What is not guaranteed thread-safe are any operations you perform on the collection that are non-atomic.
For example, this is threadsafe without any action on your part:
queue.add(obj);
or
queue.poll(obj);
However; non-atomic calls to the queue are not automatically thread-safe. For example, the following operations are not automatically threadsafe:
if(!queue.isEmpty()) {
queue.poll(obj);
}
That last one is not threadsafe, as it is very possible that between the time isEmpty is called and the time poll is called, other threads will have added or removed items from the queue. The threadsafe way to perform this is like this:
synchronized(queue) {
if(!queue.isEmpty()) {
queue.poll(obj);
}
}
Again...atomic calls to the queue are automatically thread-safe. Non-atomic calls are not.
This is probably what you're looking for in terms of thread safety & "prettyness" when trying to consume everything in the queue:
for (YourObject obj = queue.poll(); obj != null; obj = queue.poll()) {
}
This will guarantee that you quit when the queue is empty, and that you continue to pop objects off of it as long as it's not empty.
Use poll to get the first element, and add to add a new last element. That's it, no synchronization or anything else.
The ConcurentLinkedQueue is a very efficient wait/lock free implementation (see the javadoc for reference), so not only you don't need to synchronize, but the queue will not lock anything, thus being virtually as fast as a non synchronized (not thread safe) one.
Just use it as you would a non-concurrent collection. The Concurrent[Collection] classes wrap the regular collections so that you don't have to think about synchronizing access.
Edit: ConcurrentLinkedList isn't actually just a wrapper, but rather a better concurrent implementation. Either way, you don't have to worry about synchronization.

Categories

Resources