can i synchronize 2 different methods? java - java

I have some trouble with the use of the synchronized keyword in java. I do understand the part where threads get locks on methods or code blocks but I dont know how to use it in the following example.
I have got 2 different threads (Thread A and Thead B) and a Class1 that holds a list witch contains instances of Class2. The Class1.methodA() that gets called by threadA modifies the information in the list. The Class1.methodB() that gets called by threadB only uses the information in the list.
I concluded that problems that i am having in my program occur when Thread A is modifying the data in the list while Thread B is using it.
Should i create a synchronized method inside Class1 which than calls MethodA or MethodB (seems redundant to me). Or can the thread get a lock just on the specific instance of Class2 that is being modified?
I am sorry for any bad English.

Have both methods syncrhonize on the list:
methodA()
{
synchronized(list)
{
... use the list, no one else can touch it
}
... do other stuff.
}
same for methodB()
More info here.

There is a explanation about the threading here
Well, back to your question. You can actually just use the synchronize on your list and do the reading or adding in this synchronize block.
synchronized(yourList)
{
// do something
}
Otherwise I guess you can use the CopyOnWriteArrayList (API) from the java.util.concurrent package. But this is really costly, because it makes always a fresh copy of the underlying array.
CopyOnWriteArrayList<String> myArrayList = new CopyOnWriteArrayList<String>();
myArrayList .add("Stackoverflow");
Iterator<String> iterator = myArrayList .iterator();
while (iterator.hasNext())
System.out.println(iterator.next());
}
Another method would be to use the synchronizedList
List list = Collections.synchronizedList(new ArrayList());
synchronized(list) {
Iterator i = list.iterator();
while (i.hasNext())
foo(i.next());
}
But you still need the synchronized block in the end. The add and remove methods itself are atomic and thread safe, but iterating over the list is not.

Related

Does a lock on class, locks class variables too? - java

I have the below class
public class Example{
public static List<String> list = new ArrayList<String>();
public static void addElement(String val){
synchronized(list){
list.add(val);
}
}
public static synchronized void printElement(){
Iterator<String> it = list.iterator();
while(it.hasNext()){
//print element
}
}
}
Will the iterator() call in the printElement method throw ConcurrentModificationException? The basic question is if the lock on class object is acquired(as done in printElement method), will it lock the class members/ variables too? please help me with the answer.
Does a lock on class, locks class variables too? - java
Your lock is on your instance, not your class. And no, it only locks the instance.
Will the iterator() call in the printElement method throw ConcurrentModificationException?
It will if the code in that method modifies the list during the iteration. But if all of your code in that class also synchronizes, and you haven't given a reference to that list to anything outside your class, then you know that only the code in that method is running.
You'd probably be better off, though, synchronizing on the list itself. That way, even if you've given out a reference to the list, assuming all code that uses it synchronizes on it, you'll be safe from concurrent mods:
public static void printElement(){
// ^--- No `synchronized ` here unless you REALLY need it for other reasons
synchronized (list) {
Iterator<String> it = list.iterator();
while(it.hasNext()){
//print element
}
}
}
If you are giving out references and want to be really sure, either use a list returned by Collections.synchronizedList or something from the java.util.concurrent package.
No, a synchronized method does not lock the object variables, a synchronized method will lock only this.
Your code is not thread safe, since you are locking on different objects on addElement and printElement. There is nothing preventing the insertion to occur while iterating the list, if both method are called concurrently.
Will the iterator() call in the printElement method throw ConcurrentModificationException?
Yes, if addElement and printElement is called by two threads simultaneously.To avoid, ConcurrentModificationException, you could use CopyOnWriteList.
if the lock on class object is acquired(as done in printElement method), will it lock the class members/ variables too?
synchonized method printElement will aquire the lock of this object.Hence it wont allow another synchronized method or synchornized(this) block to be called at the same time, in your class, if there is any.
You never called addElement method, so locking has no effect on this code snippet. While you are iterating over a collection, if you insert/delete element to/from the same collection you get ConcurrentModificationException.
From Javadoc:
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.
ArrayList throws ConcurrentModificationException when there will be concurrently modification on the collection or while iterating in case of change in collection structure.
You should better lock the list Object resouce. if list is having getter method to access it outside, so from out side it could able to modify the structure.
synchronized (list) {
Iterator<String> it = list.iterator();
while(it.hasNext()){
//print element
}
}

Java Synchronized Collections vs Object

I'm wondering what the difference is between these ways of synchronization
List<Integer> intList = Collections.synchronizedList(new ArrayList<Integer>());
synchronized (intList) {
//Stuff
}
and using an object lock
Object objectLock = new Object();
List<Integer> intList = new ArrayList<Integer>();
synchronized (objectLock) {
//Stuff
}
The first approach makes sure that individual method calls are synchronized, and it avoids needing to manage a separate lock object. One thread can call
intList.add(3);
and another can call
intList.clear();
without a synchronized block, and it'll be properly synchronized. (Unfortunately, this doesn't help when you need to hold the lock for a group of function calls; then, you need a synchronized block around those calls.) Also, if you need to pass the list around, you can use
otherObject.doStuffWith(intList);
and
return intList;
instead of
otherObject.doStuffWith(intList, objectLock);
and
return ListAndLock(intList, objectLock);
The code you show is not necessarily thread safe yet!!
The only difference between one excerpt and the other is the object you use as a monitor for synchronization. This difference will determine which object should be used for synchronization by other threads that need access to the mutable data you're trying to protect
great read for this: java concurrency in practice

Java synchronized list for loop

Documentation on synchronizedList states that,
It is imperative that the user manually synchronize on the returned list when iterating over it:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
Failure to follow this advice may result in non-deterministic behavior.
This seems pretty clear, but I just wanted to confirm that a for each loop is prohibited. For example, I cannot do something like as follows right?
List<MyType> list = Collections.synchronizedList(new ArrayList(<MyType>));
...
synchronized(list){
for(MyType m : list){
foo(m);
m.doSomething();
}
}
Yes, you can - your enhanced for loop is basically the same as your code which explicitly uses the iterator. It boils down to the same code - it's just calling iterator() and then alternating between next() and hasNext() calls.
You can do that. The foreach loop compiles to (nearly) the same bytecode as the while loop. The keys are:
You synchronize the block around the loop because the list may change while you are iterating over it.
You use the list as the object that you are synchronizing on, since the implementation of this class locks on itself (through synchronized methods).
If possible, you might want to consider using immutability rather than synchonization.
http://docs.guava-libraries.googlecode.com/git-history/release09/javadoc/com/google/common/collect/ImmutableList.html
Of course you can, the only problem I see here is a performance issue, if your method dosomething() or foo(m) are costly to execute, you will have a performance cost. The size of your collection is also important to take in account while looping in a synchronized block, due to the fact that, when a thread acquire the lock, while in the synchronized block, looping in a huge collection will push other threads to wait.

Does a synchronized block prevent other thread access to object?

If I do something to a list inside a synchronized block, does it prevent other threads from accessing that list elsewhere?
List<String> myList = new ArrayList<String>();
synchronized {
mylist.add("Hello");
}
Does this prevent other threads from iterating over myList and removing/adding values?
I'm looking to add/remove values from a list, but at the same time protect it from other threads/methods from iterating over it (as the values in the list might be invalidated)
No, it does not.
The synchronized block only prevents other threads from entering the block (more accurately, it prevents other threads from entering all blocks synchronized on the same object instance - in this case blocks synchronized on this).
You need to use the instance you want to protect in the synchronized block:
synchronized(myList) {
mylist.add("Hello");
}
The whole area is quite well explained in the Java tutorial:
http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
Yes, but only if all other accesses to myList are protected by synchronized blocks on the same object. The code sample you posted is missing an object on which you synchronize (i.e., the object whose mutex lock you acquire). If you synchronize on different objects or fail to synchronize at all in one instance, then other threads may very well access the list concurrently. Therefore, you must ensure that all threads have to enter a synchronized block on the same object (e.g., using synchronized (myList) { ... } consistently) before accessing the list. In fact, there is already a factory method that will wrap each method of your list with synchronized methods for you: Collections.synchronizedList.
However, you can certainly use Collections.synchronizedList to wrap your list so that all of its methods are individually synchronized, but that doesn't necessarily mean that your application's invariants are maintained. Individually marking each method of the list as synchronized will ensure that the list's internal state remains consistent, but your application may wish for more, in which case you will need to write some more complex synchronization logic or see if you can take advantage of the Concurrency API (highly recommended).
here the sychronized makes sure that only one thread is adding Hello to the myList at a time...
to be more specific about synchronizing wrt objects yu can use
synchronized( myList ) //object name
{
//other code
}
vinod
From my limited understanding of concurrency control in Java I would say that it is unlikely that the code above would present the behaviour you are looking for.
The synchronised block would use the lock of whatever object you are calling said code in, which would in no way stop any other code from accessing that list unless said other code was also synchronised using the same lock object.
I have no idea if this would work, or if its in any way advised, but I think that:
List myList = new ArrayList();
synchronized(myList) {
mylist.add("Hello");
}
would give the behaviour you describe, by synchronizing on the lock object of the list itself.
However, the Java documentation recommends this way to get a synchronized list:
List list = Collections.synchronizedList(new ArrayList(...));
See: http://download.oracle.com/javase/1.4.2/docs/api/java/util/ArrayList.html

Iterator Concurrent Modifiction Exception

This code will throw Concurrent Modification Exception if the list is modified in doSomething(). Is it possible to avoid it by enclosing the code in some synchronized block?
List l = Collections.synchronizedList(new ArrayList());
// normal iteration -- can throw ConcurrentModificationException
// may require external synchronization
for (Iterator i=list.iterator(); i.hasNext(); ) {
doSomething(i.next());
}
if you are removing an item from the list, you can do it by calling iterator.remove() instead of list.remove(iterator.next())
if you are adding an item - well, create a copy of the iterated list and add it there
if the code snippet above is part of the same method, then you don't need a synchronized list or synchronized blocks - no other thread can access the local list.
You can modify a Collection while iterating over it if you do so through the Iterator interface. You can use Iterator.remove() to remove elements.
You cannot modify it while you are iterating over it. Synchronizing won't help here.
EDIT : I forgot iterator does have the remove method. So it is possible to remove.
I agree with others about Iterator and remove().
About synchronization, I wanted to add that synchronization is designed to control interactions between different threads.
It is typical for an object to have several methods synchronized, and that one would call another. So the language designers decided that the same thread would not be blocked by himself on a synchronized.
Also, thinking about it, it a thread is blocked waiting for himself, you have a magnificent starvation perspective! ;-)
So this answers one of your questions: it is not possible to avoid the problem by synchronizing your code.
Use CopyOnWriteArrayList instead of synchronized Array List
List l = Collections.synchronizedList(new ArrayList());
synchronized(l) {
// normal iteration -- can throw ConcurrentModificationException
// may require external synchronization
for (Iterator i=list.iterator(); i.hasNext(); ) {
doSomething(i.next());
}
}

Categories