简体   繁体   中英

How to handle array synchronization in Java

I have an object with an array of Integers, and a method that can modify it, locking just an element of my array:

public void setArray(Integer position, int num) {
    synchronized (myarray[position]) {
        myarray[position] = num;
    } 
}

Then I would like to calculate the average of my array, but to do this I need to "lock" the entire object, and be sure that the other threads are not executing the method setInteger, till the finish of my calculateAverage. How can I do this?

If I write: synchronized (MyObject ) {...} It won't work because I am locking different things...

Your current approach does not work; you are not locking myarray but an Integer object that was referenced from it; another thread may see updates out of order or not see updates for a while, or at all.

There is a better solution - declare myarray as AtomicIntegerArray myarray; . Updates to AtomicIntegerArray are always correctly synchronized; other threads are guaranteed to see them immediately and in the right order.

It's even better (more efficient) if you could distribute the work among the threads in a way that they do not update the same elements of the array - there is always some cost associated with thread synchronization.

First of all, the synchronization in your setArray is not going to prevent race conditions. The problem is that it replaces the object that other threads are synchronizing with another one. As a result, they are liable to synchronize on different objects.

So if you really need fine-grained (ie per cell) synchronization for some other aspect of your application, then you will need to rethink how you are doing it. AtomicIntegerArray could be the answer; see javadoc .


Now to the problem at hand: getting mutual exclusion on the entire array so that you can calculate the average. ( AtomicIntegerArray won't solve this problem!)

If we ignore cell-level locking, the solution(s) for this are straight-forward. You just get mutual exclusion on the entire array whenever you need to update it and whenever you need to access a single cell or all cells.

But this makes all array operations a concurrency bottleneck, which is what you are probably trying to avoid.

But this means that all other threads that need to gain mutual exclusion on all of the array or just a single cell of the array must to use the same mutual exclusion mechanism. Achieving entire array and single cell exclusion in the same mechanism is going to be difficulr... and very expensive compared to synchronized(array) .

A better idea would be to achieve this at a higher level. For example, use a ReadWrite lock with "read" locks representing the ability to gain a cell-level lock 1 , and the "write" lock excluding all cell-level locks. (All threads with "read" locks would need to release them before the averaging thread can do its work.)


Alternatively, ask yourself this: does it really make sense from the application perspective to compute a precise average of the entire array while it is being mutated? What is the practical use of the average, given that it could only be valid for an instant?

Maybe this means that you should calculate the average without locking the array, and accept that it is unlikely to be instantaneously accurate. Or if the average has to be instantaneously accurate, use an atomic long to hold the sum of all array elements, and have the array set operations update the sum.


1 - Alternatively, they could represent the ability to mutate the array using AtomicIntegerArray operations.

Use a ReadWrite Lock. Remember you need to read lock to read the array to calculate average etc. and the write lock to update the array.

No point in optimizing as synchronizing on a single element. This approach would fail.

There are more complicated ways to optimize such as segmenting the array across many locks and so on but for all practical purposes is not required.

readwrite lock javadoc

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM