Java: how to synchronize array accesses and what are the limitations on what goes in a synchronized condition
Asked Answered
G

5

13

I had a 2x2 array that I had two threads operating on.

it is possible to use a synchronized statement in java on an array?

how does the locking work? the java tutorial thread said that the synchronized statement works on objects, so I wasn't sure what they meant. Another site said that I could make a statement like

synchronized (array1[]){

}

Does this synchronize accesses to everything in the array so that the array is locked to other threads?

if I have a two-d Array can i use

synchronized (array1[i]) to lock one of the rows of the array?

and is it possible to lock individual array values with something like

synchronized (array1[i][j]){

}

But yeah, tips or help are greatly appreciated. Actually I already turned it in, correct or not. But I want to know for future use

Geulincx answered 8/9, 2011 at 16:1 Comment(0)
F
17

Yes, you can synchronize using an array as monitor object, because arrays (even arrays of primitives) are objects in Java.

You can synchronize a block of code on a specific monitor like this:

public void myMethod() {

    unsynchronized_statements...

    synchronized(myMonitorObject) {
        synchronized_statments...
    }

It is best practice to synchronize as few lines of code as possible.

Synchronizing code on a monitor does not affect the monitor in any way, it only affects the threads accessing the synchronized block of code. Before thread execution can enter the block of code, it must obtain 'the lock' on the monitor. The Java runtime ensures that at most one thread at a time can have 'the lock' on a monitor. So synchronizing on your array does not prohibit unsynchronized blocks of code to access it! The trick is to make sure that all the operations you don't want to happen at the same time are within blocks synchronized on the same monitor.

Since Java does not offer multi-dimensional arrays, only arrays-of-arrays, you can certainly synchronize on a nested array for more fine-grained synchronization. If you model a 2d array as an array of rows, you can only synchronize on rows, not on columns because in that example columns are not represented as separate arrays.

You can only synchronize on single array values if these are non-primitve, so Integer() instead of int. Note that Integer() is an immutable object, so you would not be able to change its value. A solution would be to create your own Cell() wrapper object with a getter and setter for the contained numeric value. This would allow you to let a thread get a lock on the Cell and safely change its value.

Because it's my day off I decided to have some fun and created a working example of what you describe. Yes, this is my idea of having fun.

Classes:

  • Matrix : representation of a 2d matrix of cells
  • Cell : wrapper for a matrix cell value
  • Operation : An abstract operation on an array of Cells
  • IncrementOperation : an Operation which increments each Cell value
  • ReverseOperation : an Operation which reverses the order of the cells
  • Main : the application

The application starts multiple operations on the same matrix. The only synchronized block of code is in the class Operation. If you remove the synchronization, the results will be wrong because two operations are manipulating the same row simultaneously.

Output when synchronized:

[105, 104, 103, 102, 101]
[110, 109, 108, 107, 106]
[115, 114, 113, 112, 111]
[120, 119, 118, 117, 116]
[125, 124, 123, 122, 121]
[130, 129, 128, 127, 126]
[135, 134, 133, 132, 131]
[140, 139, 138, 137, 136]
[145, 144, 143, 142, 141]
[150, 149, 148, 147, 146]

Example output when NOT synchronized:

[105, 4, 103, 102, 101]
[110, 9, 108, 207, 106]
[115, 14, 113, 212, 111]
[120, 19, 118, 217, 116]
[125, 124, 123, 122, 121]
[130, 129, 128, 127, 126]
[135, 34, 133, 232, 131]
[140, 139, 138, 137, 136]
[145, 144, 143, 142, 141]
[150, 149, 148, 147, 146]

Note that I added some Thread.sleep() statements in the operation implementations to make the difference between synchronized and unsynchronized execution more obvious.

Ferne answered 8/9, 2011 at 16:16 Comment(4)
You cannot synchronize on primitives. A synchronized block required a object so that it can use it's associated lock.Alleviator
Where did I say you can synchronize on primitives?Ferne
Hi there. I didn't want to sound mean, just saw your first line "Yes, you can synchronize using an array as monitor object, because arrays (even of primitives) are objects in Java." You said that you can synch on arrays because they are objects. That's right. But also added that event primitives are threated as objects, but they are not. Regards, Tiberiu.Alleviator
Thanks for the clarification, I updated my answer to disambiguate.Ferne
T
4

No, synchronizing this way only means you are locking on the array object, not that you are actually synchronizing access to its methods. If your array is visible to others, they may still access/modify its contents regardless of whether or not it is being locked on. Only they can't lock on it at the same time - if they attempt to (from a different thread), they will be blocked until the lock is released by its original acquirer.

If you want to ensure that only one thread is accessing your array (or one element of it) at a time, you need to encapsulate it in a class and synchronize all public class methods which manipulate the array. (You may lock on the array for this purpose, though, if you want to - the simpler and usual approach is to declare the methods themselves as synchronized, in which case their content is synchronized on this, the enclosing object).

class ArrayWrapper {
  private int[] array = ...;

  public void setValue(int index, int value) {
    synchronized (array) {
      array[index] = value;
    }
  }

  public int getValue(int index) {
    synchronized (array) {
      return array[index];
    }
  }

  ...
}
Tredecillion answered 8/9, 2011 at 16:10 Comment(2)
+1: It usually a good idea to make a field you are using as a lock final. If it can't be final you could have a bug.Hospodar
I just implemented this way, to write my first bit of synchronized code and it fixed my bug, so thankyou.Giddens
S
3

The synchronizedkeyword only works with Objects.

Synchronizing on the array only locks on the array (in Java an array is an object).

If you synchronize on some array individual element, suppousing they are objects and not primitives, that is another different lock. You can have one without the other, and the inverse is also true. You can´t synchronize on a primitive.

If you need to prevent concurrent modification of the array, synchronize on some object in every access to the array. You can use whichever object you want for this purpose, but it has to be the same for the thing to work. Note that if you access a shared resource with synchronize and in other parts of the code you access without synchronized or synchronizing on other object, then that is useful for nothing.

Salonika answered 8/9, 2011 at 16:16 Comment(0)
H
1

When you synchronise an Object or array, you are preventing another thread from synchronising than same object. This doesn't prevent you from using the object and no other operation is "locked" You have to ensure you locked the object first in a consistent manner for it to "lock" the object.

Hospodar answered 8/9, 2011 at 16:55 Comment(0)
W
0

in my opinon , using arrays for synchronization is not good incase the array is not fixed . i mean if array is cloned , then it creates a new object ,then it is possible that , the data in consistency /conflict can happe.
for example, we have two methods add() - add element into array and remove() remove element from array , while addiing element, if array capacity increased to accomidate new value, at the same time, if remove is using lock on new array object , though your add is not finished. that makes some data inconsistency.

Worried answered 12/10, 2022 at 6:27 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Etana

© 2022 - 2024 — McMap. All rights reserved.