synchronized in java - Proper use
Asked Answered
S

5

0

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;
}
Stentorian answered 9/6, 2014 at 21:1 Comment(6)
I'm pretty sure you can put synchronized on static methods too...Cockney
@user3580294 yes, I know it, but i don't need to synchronized static methods...Stentorian
If you want to understand more, read a tutorial and test the code.Fiedler
@LuiggiMendoza I'm new in this site, where can I find tutorial on it? Note: The code I wrote, my question is in relation to multiple processesStentorian
This site is for specific programming question. This question is not very specific, the answer can be found in tutorials and mid-long explanations. Also, if you want/need a class that supports adding multiple objects and used in concurrency, use a concurrent collection from java.util.concurrent package. Usually, you use a BlockingQueue implemented by LinkedBlockingQueue.Fiedler
@LuiggiMendoza O.K. thank you very much! I'll be more specific next timeStentorian
R
5

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.

Reynold answered 9/6, 2014 at 21:15 Comment(7)
I'm pretty sure you'd need to synchronize for isEmpty()... Might be possible that in between loading the backing array's size and performing the actual comparison the array could be cleared by another threadCockney
@user3580294 or even better: do not reinvent the wheel and use a real collection that supports concurrency from java.util.concurrent package.Fiedler
@user3580294 It was my fear ... Do you think any method that affects the bone variables needs synchronized?Stentorian
I see your point about isEmpty(), but I think the unsynchronized behavior is just as good. In either case, the answer you get is reflective of the state of the array "at some point in time" close to when you called it. If you want to do something with that answer that relied on it still being true, you'd have to synchronize more of the code surrounding it anyway.Reynold
I believe we are all reinforcing the point that "this stuff is hard to get right"Reynold
@Reynold YES you right! I learn this stuff in basic, so my question was not specific enoughStentorian
@Stentorian Generally you'd need to synchronize any methods that rely on mutable stateCockney
C
5

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.

Companionway answered 9/6, 2014 at 21:13 Comment(0)
R
5

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.

Reynold answered 9/6, 2014 at 21:15 Comment(7)
I'm pretty sure you'd need to synchronize for isEmpty()... Might be possible that in between loading the backing array's size and performing the actual comparison the array could be cleared by another threadCockney
@user3580294 or even better: do not reinvent the wheel and use a real collection that supports concurrency from java.util.concurrent package.Fiedler
@user3580294 It was my fear ... Do you think any method that affects the bone variables needs synchronized?Stentorian
I see your point about isEmpty(), but I think the unsynchronized behavior is just as good. In either case, the answer you get is reflective of the state of the array "at some point in time" close to when you called it. If you want to do something with that answer that relied on it still being true, you'd have to synchronize more of the code surrounding it anyway.Reynold
I believe we are all reinforcing the point that "this stuff is hard to get right"Reynold
@Reynold YES you right! I learn this stuff in basic, so my question was not specific enoughStentorian
@Stentorian Generally you'd need to synchronize any methods that rely on mutable stateCockney
E
3

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.
Exciting answered 9/6, 2014 at 21:11 Comment(0)
E
2

+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).

Ealasaid answered 10/6, 2014 at 14:12 Comment(0)
P
0

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.

Propensity answered 9/6, 2014 at 21:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.