ZoharYosef
ZoharYosef

Reputation: 257

synchronized in java - Proper use

I'm building a simple program to use in multi processes (Threads).

My question is more to understand - when I have to use a reserved word synchronized?

Do I need to use this word in any method that affects the bone variables?

I know I can put it on any method that is not static, but I want to understand more.

thank you!

here is the code:

public class Container {
// *** data members ***
public static final int INIT_SIZE=10;  // the first (init) size of the set.
public static final int RESCALE=10;   // the re-scale factor of this set.
private int _sp=0;
public Object[] _data;
/************ Constructors ************/
public Container(){
    _sp=0;
    _data = new Object[INIT_SIZE];
}
public Container(Container other) {  // copy constructor
    this();
    for(int i=0;i<other.size();i++) this.add(other.at(i));
}

/** return true is this collection is empty, else return false. */
public synchronized boolean isEmpty() {return _sp==0;}

/** add an Object to this set */
public synchronized void add (Object p){
    if (_sp==_data.length) rescale(RESCALE);
    _data[_sp] = p;  // shellow copy semantic.
    _sp++;
}   

/** returns the actual amount of Objects contained in this collection */
public synchronized int size() {return _sp;}

/** returns true if this container contains an element which is equals to ob */
public synchronized boolean isMember(Object ob) {
    return get(ob)!=-1;
}

/** return the index of the first object which equals ob, if none returns -1 */
public synchronized int get(Object ob) {
    int ans=-1;
    for(int i=0;i<size();i=i+1)
        if(at(i).equals(ob)) return i;
    return ans;
}

/** returns the element located at the ind place in this container (null if out of range) */
public synchronized Object at(int p){
    if (p>=0 && p<size()) return _data[p];
    else return null;
}

Upvotes: 0

Views: 1098

Answers (5)

Solomon Slow
Solomon Slow

Reputation: 27115

+1 for everybody who said read a tutorial, but here's a summary anyway.

You need mutual exclusion (i.e., synchronized blocks) whenever it is possible for one thread to create a temporary situation that other threads must not be allowed to see. Suppose you have objects stored in a search tree. A method that adds a new object to the tree probably will have to reassign several object references, and until it finishes its work, the tree will be in an invalid state. If one thread is allowed to search the tree while another thread is in the add() method, then the search() function may return an incorrect result, or worse (maybe crash the program.)

One solution is to synchronize the add() method, and the search() method, and any other method that depends on the tree structure. All must be synchronized on the same object (the root node of the tree would be an obvious choice).

Java guarantees that no more than one thread can be synchronized on the same object at any given time. Therefore, no more than one thread will be able to see or change the internals of the tree at the same time, and the temporary invalid state created inside the add() method will be harmless.


My example above explains the principle of mutual exclusion, but it is a simplistic and inefficient solution to protecting a search tree. A more practical approach would use reader/writer locks, and synchronize only on interesting parts of the tree rather than on the whole thing. Practical synchronization of complex data structures is a hard problem, and whenever possible, you should let somebody else solve it for you. E.g., If you use the container classes in java.util.concurrent instead of creating your own data structures, you'll probably save yourself a lot of work (and maybe a whole lot of debugging).

Upvotes: 2

M A
M A

Reputation: 72844

You can check the following documentation about synchronized methods: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

By adding the synchronized keyword two things are guaranteed to happen:

First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.

So whenever you need to guarantee that only one thread accesses your variable at a time to read/write it to avoid consistency issues, one way is to make your method synchronized.

Upvotes: 5

Dariusz
Dariusz

Reputation: 371

You need to protect variables that form the object's state. If these variables are used in static method, you have to protect them as well. But, be careful, following example is wrong:

private static int stateVariable = 0;
//wrong!!!!
public static synchronized void increment() {
  stateVariable++;
}

public synchronized int getValue() {
  return stateVariable;
}

It seems that above is safe, but these methods operate on different locks. Above is more or less corresponds to following:

private static int stateVariable = 0;
//wrong!!!!
public static void increment() {
  synchronized (YourClassName.class) {
    stateVariable++;
  }
}

public synchronized int getValue() {
  synchronized (this) {
    return stateVariable;
  }
}

Notice that different locks are used when mixing static and object methods.

Upvotes: 0

jfrank
jfrank

Reputation: 733

Making a class safe for multi-threaded access is a complex subject. If you are not doing it in order to learn about threading, you should try to find a library that does it for you.

Having said that, a place to start is by imagining two separate threads executing a method line by line, in an alternating fashion, and see what would go wrong. For example, the add() method as written above is vulnerable to data destruction. Imagine thread1 and thread2 calling add() more or less at the same time. If thread1 runs line 2 and before it gets to line 3, thread2 runs line 2, then thread2 will overwrite thread1's value. Thus you need some way to prevent the threads from interleaving like that. On the other hand, the isEmpty() method does not need synchronization since there is just one instruction that compares a value to 0. Again, it is hard to get this stuff right.

Upvotes: 5

Ale Sequeira
Ale Sequeira

Reputation: 2039

My advice to you is to first read Oracle's concurrency tutorial.

A few comments:

  • Having all your methods synchronized causes bottlenecks
  • Having _data variable public is a bad practice and will difficult concurrent programming.
  • It seems that you are reimplementing a collection, better use existing Java's concurrent collections.
  • Variable names would better not begin with _
  • Avoid adding comments to your code and try to have declarative method names.

Upvotes: 3

Related Questions