In my case, I have two solutions to my problem. One is to allow the threads to modify the lists, and one is to defer the changes by saving them and execute them single-threaded after everything. I think it will be faster to use synchronization since I will not be doing many changes per update, like 80% of the time it will be 0 changes but sometimes several in a single frame. The chance of two lists being modified in the same frame is extremely low, but if synchronization is as expensive as you say…
Concerning how much work I actually do in each change, I realized that I might have to keep the lists sorted, since the order of the objects in them may have an effect if the scripts used in the game are order-dependent (I need determinism for network synchronization and replaying). I might therefore have to switch from ArrayList to some kind of sorted list or set, which would of course take more time to change…
In the end, I guess only an actual benchmark would be able to give me an answer. Thanks for all the quick responses!