I am relatively new to concurrency. I am practicing concurrency from Oracle website. I am stucked at the following example:-
public class MsLunch {
private long c1 = 0;
private long c2 = 0;
private Object lock1 = new Object();
private Object lock2 = new Object();
public void inc1() {
synchronized(lock1) {
c1++;
}
}
public void inc2() {
synchronized(lock2) {
c2++;
}
}
}
I want to know how is this type of lock useful over using synchronized(this) type lock? And in which situations should this type of lock be preferred?
Thanks
It's useful when you have a single object that needs a finer resolution of exclusion than the object itself. In other words, an object with multiple resources that need to be protected but not necessarily from each other.
Being bought up in the pthreads world, this is easy to understand since the mutex and it's protected resource tended to be always decoupled - there was never this handy shorthand found in Java for using an object as the lock.
As an example, say each object has a array of a thousand integers and you want to lock a group of a hundred at a time (0xx, 1xx, and so on) for maximum concurrency.
In that case, you create ten objects, one per group of a hundred, and you can lock individual parts of the array. That way, if you have a thread fiddling about with the 0xx and 4xx blocks, it won't stop another thread from coming in and doing something with the 7xx block.
Now that's a pretty contrived example but the concept does occasionally show up in reality.
In the specific example you've given, only one thread at a time can come in and increment c1 concurrently, but a lock on lock1 still permits another thread to come in and change c2.
With a object (this) lock, concurrency would be reduced because c1 and c2 couldn't be updated concurrently despite the fact that there is no conflict.
Object lock is nothing but you are locking the critical section explicitly by an object. synchronized (this) describes that you are locking the critical section by the current object.
Having two separate locks for inc1 and inc2 is useful in situations where you want to make sure that no two concurrent threads can both call the same method at the same time, but where you do want to allow two concurrent threads to call different methods on the same object.
In your example, if thread 1 calls inc1, thread 2 is blocked from calling inc1 until thread 1 is done. However, thread 2 is free to call inc2.
Related
I am trying the below code snippet which is giving expected output.But I am curious to know how many lock objects I am creating 1 or 2?
package com.practice;
class A{
String lock="";
A(String lock){
this.lock = lock;
}
A(){ }
public void printMe(int x) {
int counter = x;
synchronized (lock) {
System.out.println(++counter);
}
}
}
public class MultiThreadingPractice {
public static void main(String[] args) {
A a = new A("1");
Thread t1=new Thread(() -> {
a.printMe(1);
});
a.lock = new String();
Thread t2=new Thread(() -> {
a.printMe(1);
});
t1.start();
t2.start();
}
}
Should locks in multi threading always remain immutable? Yes.
You're using a String (any Object would do) as a lock. When you assign a new value (new String) to the lock, that means you have more than one lock instance around. It's ok as long as all threads are synchronizing on the same lock instance, but there is nothing overt in your class A code to ensure that is the case.
In your actual use in the example, you're safe. Since no thread get started until after you've finished setting the lock to the third and last instance, nothing will be trying to sync on the lock until it's stable. (3 instances: the first is the initialization to the empty String; the second is to the supplied constructor argument "1"; and the third is the explicit assignment, to a different empty String). So, though this code "works", it only works by what I refer to as "coincidence", i.e., it's not thread-safe by design.
But let's assume a case where you start each thread immediately after you construct it. This means you'd be reassigning the lock member after t1 was running but before t2 was even created.
After a while both threads will be synchronizing on the new lock instance, but for a period around the point at which you switched the lock, thread t1 could be and probably is in the synchronized(lock) { ... } clause using the old lock instance. And around that time, thread t2 could execute and attempt to synchronize on the new lock instance.
In short, you've created a timing window (race hazard) in the mechanism that you intend to use to eliminate timing windows.
You could arrange a further level of synchronization that allows you to replace the lock, but I am unable to imagine any straightforward situation where that would be necessary, useful, or sensible. Much better to allocate one lock before any contention can occur and then stick to that one lock.
P.S. "How many locks am I creating?" 3. Though the first two are never used.
curious to know how many lock objects I am creating 1 or 2?
This line in your program creates a single String instance when the program is loaded, and both of your A instances start out with a reference to the same String.
String lock="";
This line creates a second String instance, because new String(...) always creates a new object, regardless of whether or not some other String with the same value has been interned.
a.lock = new String();
Should locks in multi threading always remain immutable? No.
The typical way to synchronize is to use synchronized methods, not separate locks. This approach is less error-prone and therefore preferred. It is equivalent to use current object as lock:
synchronized(this) {
...
}
and since this object is not usually immutable, we can conclude that using mutable objects as locks is a common practice.
What you are doing in your code, when you change the reference to the lock object (yes, you are changing the reference and not the lock object itself), is a very bad approach. It provokes programming errors.
I was reading on official tutorial on multithreading from oracle and I came cross this example (assuming c1 and c2 are never used together):
public class MsLunch {
private long c1 = 0;
private long c2 = 0;
private Object lock1 = new Object();
private Object lock2 = new Object();
public void inc1() {
synchronized(lock1) {
c1++;
}
}
public void inc2() {
synchronized(lock2) {
c2++;
}
}
}
}
It is said that by using lock 1 & lock 2, it helps to reduce unnecessary blocking as compare to using the word this in the synchronized block.
However, I don't really see how this helps to reduce blocking as they have no dependency on each other. I have multiple threads each running these two methods at the same time and the performance is rather similar when I use the lock objects and this keyword.
Can someone help to explain my confusion here? Love to see the explanation with an example to illustrate the difference clearly.
Adding on to the discussion here, this post helped to clarify my doubts as well. Key point: Putting synchronized on a method means the thread has to acquire the lock on the object instance before entering that method
You are using two different locks - one to protect inc1 and a different one to protect inc2. This means that thread X can run inc1 while another thread is running inc2. Had they used the same lock (regardless whether it's this or a different lock object), you would not be able to run them both concurrently. Thus, in theory at least, having two different locks should increase your performance in this scenario.
This question already has answers here:
Avoid synchronized(this) in Java?
(23 answers)
Closed 7 years ago.
I am reading the Oracle tutorials about multithreading programming in Java. I don't understand why should I create a new object to sync the some part of code? For what reason does the creation of new dummy object serve?
I do understand that creating these two objects will prevent compiler from reordering the code segment guarded by the construction syncronized(lock1){}
However, I would like to know can I use any other objects (except MsLunch) in the construction syncronized(lock1){} ?
What is the motivation behind introducing such construction syncronized(lock1){} ?
Here is the piece of code, I am concerned with:
public class MsLunch {
private long c1 = 0;
private long c2 = 0;
// what is the purpose of these two objects? how do they serve as locks?
private Object lock1 = new Object();
private Object lock2 = new Object();
public void inc1() {
synchronized(lock1) {
c1++;
}
}
public void inc2() {
synchronized(lock2) {
c2++;
}
}
}
First some basics:
The synchronization object is used as a key to open a door to a restricted area (the synchronization block).
As long as a thread entered this restricted area it holds the monitor (lock) so that no other thread can enter. When a thread exits the restricted area it releases the monitor and another thread can take it.
This means that each synchronization block that uses the same synchronization object will prevent other thread to enter until the monitor is available (unlocked).
For what reason does the creation of new dummy object serve?
The reason is that you should use objects that are not accessible by others objects than the ones that use them. That's why the synchronization objects are private. If they would be accessible by others, other might use them in their synchronization blocks somewhere in the application. If the synchronizcation object is e.g. public then every other object can use it. This might lead to unexpected usage and might result in deadlocks.
So you should make sure who will get a reference to the synchronization object.
The lock is accessed by the threads to check if the code is currently "in use" or if they can execute it after locking the object themselves.
You may think it could be automatic, but it has a use compilers couldn't infer : you can use the same lock to synchronize multiple code blocks, restraining the access to any of them at the same time.
In my opinion, dummy Object just represents the point of synchronization.
For synchronize different threads, you must be able to declare point of synchronization and(if it is needed) give access to this point from different parts of the code. For example:
private Object lock = new Object();
public void inc1() {
synchronized(lock) {
c1++;
}
}
public void inc2() {
synchronized(lock) {
c2++;
}
}
In this example shown the usage of same point of synchronization from different part of code.
And because Java is Object oriented language i.e. unit of language in Java is Object, we have exactly such a construction.
By the way, you can use any object in as point of synchronization. You can do even this:
public void inc1() {
synchronized(this) {
c1++;
}
}
what is the purpose of these two objects? how do they serve as locks?
As shown in your code, inc1() and inc2() can only be invoked by one thread each. This means that c1 and c2 can be increased just once per thread - but simultaneuosly by two different threads (because both threads synchronize on different objects).
If both blocks were synchronized like this synchronized(lock1), c1 and c2 could not be increased simultaneuosly.
i'm currently studying the multithreading concept thoroughly and i'v noticed that whenever a synchronized block is discussed, the lock on this object is acquired. e.g:
synchronized(this) {}
but, is there any reason to give another object as the argument for synchronized? or is it an inadvisable pattern?
An example why locking on something else might be beneficial:
final List<Object1> firstList = new List<>();
final List<Object2> secondList = new List<>();
// ...
public Object readFromListOne() {
synchronized(firstList) {
return firstList.remove(0);
}
}
public Object readFromListTwo() {
synchronized(secondList) {
return secondList.remove(0);
}
}
Here threads can access both lists simultaneously, while a synchronized(this) would have locked both calls, even though it isn't necessary.
Btw: a concurrent list will render all this synchronization obsolete
You can use a third party object as a lock. Generally such objects can be used to achieve synchronization to shared resources between different objects, which will be forced to acquire this third party object lock before executing certain piece of code.
You can use a common object as follows.
static final Object lock=new Object();
Then you can parse this into synchronized block as follows
synchronized(lock){
}
Only requirement here is you have to share common object. Then each path(different object) locked based on this object.
I think you are having issue with why we use other object.
If we want to locked different path by different Threads we have to locked each path. So we have to use third object. Then when one object quires that lock object other threads has to wait until that lock is resealed. But same thread which acquire the lock can continue.
synchronized(this) {}
That means that any other thread that synchronizes on this will have to release/wait until you release/wait the lock before it can proceed.
synchronized(somethingElse) {}
That means the lock happens on now with somethingElse.
So there is a clear difference and depends on what you are synchronized.
I am pretty new to thread-safe programming, and was wondering if I have something like below, would this be safe from deadlock once compiled and run?
public class Foo
{
protected CustomClass[] _mySynchedData = new CustomClass[10];
public void processData()
{
synchronized(_mySynchedData) {
// ...do stuff with synched variable here
}
}
}
public class Bar extends Foo
{
#Override
public void processData()
{
synchronized(_mySynchedData) {
// perform extended functionality on synched variable here
// ...then continue onto parent functionality while keeping synched
super.processData();
}
}
}
Bar testObj = new Bar();
// Deadlock?
testObj.processData();
Your code only display a single thread.
With only one thread, there's no way you can get any deadlock.
Added:
Java language supports what they officially call reentrant synchronization.
It basically means that a single thread can reacquire a lock it already owns.
Your question is what happens when you synchronize two times on the same object.
The answer is: Java will check first which thread owns the monitor (that's the internal data structure on which synchronized operates). Since the owner thread is the same as the current thread, Java will continue.
Deadlocks can only happen if you have two monitors and you try to lock them in different orders in different threads.
The lock taken by the Java synchronized keyword supports nesting, so you don't risk a deadlock by synchronizing on the same object multiple times in the same thread.
RichN is correct in that your code only contains a single thread and hence deadlock is impossible. Also note that for a deadlock to occur you need to have multiple threads acquiring multiple locks (albeit in a different order) for a deadlock to occur.
Your code currently only references one lock: The one associated with _mySynchedData. The fact that you attempt to lock it twice does not matter as locks in Java are reentrant.