Synchronizing threads to avoid ArrayIndexOutOfBoundsException - java

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.

Related

Java when to use a multi threaded approach? [duplicate]

My main thread has a private LinkedList which contains task objects for the players in my game. I then have a separate thread that runs every hour that accesses and clears that LinkedList and runs my algorithm which randomly adds new uncompleted tasks to every players LinkedList. Right now I made a getter method that is synchronized so that I dont run into any concurrency issues. This works fine but the synchronized keyword has a lot of overhead especially since its accessed a ton from the main thread while only accessed hourly from my second thread.
I am wondering if there is a way to prioritize the main thread? For example on that 2nd thread I could loop through the players then make a new LinkedList then run my algorithm and add all the tasks to that LinkedList then quickly assign the old LinkedList equal to the new one. This would slightly increase memory usage on the stack while improving main thread speed.
Basically I am trying to avoid making my main thread use synchronization when it will only be used once an hour at most and I am willing to greatly degrade the performance of the 2nd thread to keep the main threads speed. Is there a way I can use the 2nd thread to notify the 1st that it will be locking a method instead of having the 1st thread physically have to go through all of the synchronization over head steps? I feel like this would be possible since if that 2nd thread shares a cache with the main thread and it could change a boolean denoting that the main thread has to wait till that variable is changed back. The main thread would have to check that boolean every time it tries run that method and if the 2nd thread is telling it to wait the main thread will then freeze till the boolean is changed.
Of course the 2nd thread would have to specify which object and method has the lock along with a binary 0 or 1 denoting if its locked or not. Then the main thread would just need to check its shared cache for the object and the binary boolean value once it reaches that method which seems way faster than normal synchronization. Anyways this would then result in them main thread running at normal speed while the 2nd thread handles a bunch of work behind the scenes without degrading main thread performance. Does this exist if so how can I do it and if it does not exist how hard would it actually be to implement?
Premature optimization
It sounds like you are overly worried about the cost of synchronization. Doing a dozen, or a hundred, or even a thousand synchronizations once an hour is not going to impact the performance of your app by any significant amount.
If your concern has not yet been validated by careful study with a profiling tool, you’ve fallen into the common trap of premature optimization.
AtomicReference
Nevertheless, I can suggest an alternative approach.
You want to replace a list once an hour. If you do not mind letting any threads continue using the current list already accessed while you swap out for a new list, then use AtomicReference. An object of this class holds the reference to another object of a specified type.
I generally like the Atomic… classes for thread-safety work because they scream out to the reader that a concurrency problem is at hand.
AtomicReference < List < Task > > listRef = new AtomicReference<>( originalList ) ;
A different thread is able to replace that reference to the old list with a reference to the new list.
listRef.set( newList ) ;
Access by the other thread:
List< Task > list = listRef.get() ;
Note that this approach does not make thread-safe the payload, the list itself. But you claim that only a single thread will ever be manipulating the content of the list. You claim a different thread will only replace the entire list. So this AtomicReference serves the purpose of replacing the list in a thread-safe manner while making the issue of concurrency quite obvious.
volatile
Using AtomicReference accomplishes the same goal as volatile. I’m wary of volatile because (a) its use may go unnoticed by the reader, and (b) I suspect many Java programmers do not understand volatile, especially since its meaning was redefined.
For more info about why plain reference assignment is not thread-safe, see this Question.

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.

How does thread synchronization work in Kotlin?

I have been experimenting with Kotlin synchronization and I do not understand from the docs on how the locking mechanism works on thread synchronization over common resources and thus attempted to write this piece of code which further complicates my understanding.
fun main() {
val myList = mutableListOf(1)
thread {
myList.forEach {
while (true) {
println("T1 : $it")
}
}
}
thread {
synchronized(myList) {
while (true) {
myList[0] = 9999
println("**********\n**********\n**********\n")
}
}
}
}
myList is the common resource in question.
The first thread is a simple read operation that I intend to keep the resource utilized in read mode. The second is another thread which requests a lock in order to modify the common resource.
Though the first thread does not contain any synchronization, I would expect it to internally handle this so that a while a function like map or forEach is in progress over a resource, another thread should not be able to lock it otherwise the elements being iterated over may change while the map/forEach is in progress (even though that operation may be paused for a bit while another thread has a lock over it).
The output I see instead shows that both the threads are executing in parallel. Both of them are printing the first element in the list and the stars respectively. But in the second thread, even though the stars are being printed, myList[0] is never set to 9999 because the first thread continues to print 1.
Threading and synchronisation are JVM features, not specific to Kotlin. If you can follow Java, there are many resources out there which can explain them fully. But the short answer is: they're quite low-level, and tricky to get right, so please exercise due caution. And if a higher-level construction (work queues/executors, map/reduce, actors...) or immutable objects can do what you need, life will be easier if you use that instead!
But here're the basics. First, in the JVM, every object has a lock, which can be used to control access to something. (That something is usually the object the lock belongs to, but need not be...) The lock can be taken by the code in a particular thread; while it's holding that lock, any other thread which tries to take the lock will block until the first thread releases it.
And that's pretty much all there is! The synchronised keyword (actually a function) is used to claim a lock; either that belonging to a given object or (if none's given) 'this' object.
Note that holding a lock prevents other threads holding the lock; it doesn't prevent anything else. So I'm afraid your expectation is wrong. That's why you're seeing the threads happily running simultaneously.
Ideally, every class would be written with some consideration for how it interacts with multithreading; it could document itself as 'immutable' (no mutable state to worry about), 'thread-safe' (safe to call from multiple threads simultaneously), 'conditionally thread-safe' (safe to call from multiple threads if certain patterns are adhered to), 'thread-compatible' (taking no special precautions but callers can do their own synchronisation to make it safe), or 'thread-hostile' (impossible to use from multiple threads). But in practice, most don't.
In fact, most turn out to be thread-compatible; and that applies to much of the Java and Kotlin collection classes. So you can do your own synchronisation (as per your synchronized block); but you have to take care to synchronise every possible access to the list -- otherwise, a race condition could leave your list in an inconsistent state.
(And that can mean more than just a dodgy value somewhere. I had a server app with a thread that got stuck in a busy-loop -- chewing up 100% of a CPU but never continuing with the rest of the code -- because I had one thread update a HashMap while another thread was reading it, and I'd missed the synchronisation on one of those. Most embarrassing.)
So, as I said, if you can use a higher-level construction instead, your life will be easier!
Second thread is not changing the value of the first list element, as == means compare, not assign. You need to use = tio change the value e.g. myList[0] = 9999. However in your code it's not guaranteed that the change from the second thread will become visible in the first thread as thread one is not synchronising on myList.
If you are targeting JVM you should read about JVM memory model e.g. what is #Volatile. You current approach does not guarantee that first thread will ever see changes from the second one. You can simplify your code to below broken example:
var counter = 1
fun main() {
thread {
while (counter++ < 1000) {
println("T1: $counter")
}
}
thread {
while (counter++ < 1000) {
println("T2: $counter")
}
}
}
Which can print strange results like:
T2: 999
T1: 983
T2: 1000
This can be fixed in few ways e.g. by using synchronisations.

Synchronize ArrayList in or outside of while loop?

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.

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

Categories

Resources