If you had thread #1 that iterates over a list and uses the data to render 2d graphics, and then thread #2 that is deleting items, adding items, but mostly changing the value of items in that list, which option is better/more efficient?
Option 1:
List<Object> list1 = new ArrayList<Object>();
List<Object> list2 = new ArrayList<Object>();
// Thread 2
ArrayList<Object> newData = new ArrayList<Object>();
newData.add(new Object());
list2 = newData;
// Thread 1
list1 = list2;
for (Object o : list1) {
// use data to render
}
Option 2:
List<Object> list = Collections.synchronizedList(new ArrayList<Object>());
// Thread 2
synchronized(list) {
// add, remove, change values
}
// Thread 1
synchronized(list) {
for (Object o : list) {
// use data to render
}
}
I really donât know a whole lot about this stuff but my fear is that in the second option, thread 1 could be trying to iterate the list and itâs locked so thread 1 runs slow and this is visible because itâs being rendered.
Option 1 is more efficient, but note that on your âlist1 = list2â line you must cross a synchronization barrier or you risk your rendering thread reading incomplete data.
Youâre correct about option #2 - the technical term for this is âlock contentionâ and it can be very detrimental to performance.
In general, you could probably improve on both of these patterns, although option #1 isnât that bad if the list hand-off is properly synchronized (this isnât unlike the buffer swap chains used to send a rendered image from your GPU to your display).
Ah okay thatâs what I thought, some people were telling me option 2 and somebody told me to use a copyonwritearray even though i said i would be iterating the list every 16 ms and updating the list on the other thread every 20 ms. This is for a clientâs data from a server for a multiplayer game. Just out of curiosity would you say this is an advanced topic or pretty basic java stuff?
Push the changes onto a queue from the network thread. Handle however many of them you can from whatever thread is handling them.
Two threads sharing the same list is usually a fundamental design issue.
Edit: and note that CopyOnWriteArrayList is recommended by folks exactly because you say you will be iterating over it a lot. Itâs writes that are âexpensiveâ on a copy on write array list because it⌠copies on write.
I concur with @pspeed about using the built in queues for this. I find that many âmultiple threads sharing dataâ designs can be easily eliminated by sharing data via queues.
As far as whether this is basic or advanced, Iâd generally put anything multithreaded squarely in the advanced category because of the high number of incredibly subtle ways to get into trouble with multiple threads (in any language, not just Java - Java is actually one of the best languages for easier multithreading, in my experience). The best way to safely multithreading is never to do it - the second best way (if you really need multiple threads), is often to use a design where threads only interact via a few well-defined and simply used handoff points (like queues).
is there some easy way to avoid execution âhard task threadsâ in same Core as âJME render threadâ?
lest say there are 4 Cores, run 3 new âhard task threadsâ, but sometimes if other application run hard task too, then one of them might go into ârender thread coreâ.
what i thought was just âpausing/dopping thread if fps drop detectedâ, but it sounds like ugly solution.
so i just ask if someone know good solution to run hard task threads and make them avoid render thread core.
Threads work in cycles of operations. Or time if you prefer. When a thread is not busy it will âgive upâ that time to another thread. In that way 6 threads can run simoiltaneously - as far as the user is concerned.
If you have four cores and four threads youâre usually fine, but not necessarily as there are always background tasks from within the OS. A good rule of thumb would be core count minus 1 to leave some breathing space, but since the OS and itâs functions are out of your control itâs only an educated guess.
If you are satisfied that your OS overhead is low, thread count - 1 should be perfectly fine. Ignore hyperthreads. They are not real threads. They will use spare cycles, and are great for say encoding but generally useless to count as a âgamingâ thread.
I made a couple of BlockingQueue<ArrayList<Object>> that thread2 is using to push different kinds of updates to thread1, and thread1 is doing something like while (!blockingQueue.isEmpty()) { every loop, does this look fine? @pspeed
BlockingQueue is dangerous because it will block when full⌠but maybe thatâs desirable.
Pushing whole lists is dangerous because itâs super tempting to keep a local reference to those lists and pretend you can still do something with them.
If you are creating these lists just to push onto the queue then you donât really have that issue⌠but then why create the lists?
I keep coming back to the fact that it feels like something a step back from here already has design issues. Like, youâve painted yourself into a corner and are trying to figure out the best way to get out of the room without smearing the paint.
Itâs a list of some updated players, like just really basic things like their x and y. One list is one whole update from the server, and i think just getting really simple things like each players new x and y from the new list and transferring them to the existing list that is used to render should be extremely fast and easily done before each frame, right? but if not, im throwing out all the piled up update lists except for the most recent one, if the server lagged or something. I donât think Iâve painted myself in a corner, one thread is constantly receiving updated info about the players from the server, and I just need a thread-safe way to transfer that data to the clientâs render threadâs lists of data, and i thought this is how you said i should do it
I thought it just made more sense to put all the updated players into a list rather than send them all seperately into the queue, and then on the other side you could distinguish what was one whole update. Iâll take a look at those, thanks again for your help
One-off lists may seem wasteful but itâs the only way to do what you are proposing (aside from some other custom one-off object). But the key is not to reuse these and to truly create them each time.