Is the locking object used for synchronization arbitrary or is there reasoning behind choosing a specific object?
Why would you lock an object? Because it is shared among various threads. That's all there is. How you implement locking and threading is probably the difficult part, as opposed to choosing which object to lock on.
You'd be better off using one of the more modern locking techniques where much of the complexity and pitfalls have been removed/smoothed over. Package java.util.concurrent.locks would be a good start.
Your question is rather unclear.
You may be referring to a Semaphore object as a lock. You may also be referring to synchronized objects.
1) A semaphore may as well arbitrary object. It's intended purpose is that it can be used to hold threads at the semaphore until other threads release it.
2) Synchronized objects make all of their functions atomic: If a thread is operating on the object, the other object waits to complete its own function. This is usually implemented using a semaphore internally.
Semaphores are the objects used to solve synchronization problems.
The locking object needs to represent the exclusive part.
if you lock the whole object meaning using it exclusively by an thread, you may use the object "this" to lock. This is the way "synchronize" work on methods work.
public class A
{
public synchronized void do1 ()
{
...
}
public synchronized void do2 ()
{
...
}
}
if your object just has some set of members which should be used exclusively, you need separate (explicit) locking objects
public class B
{
private X x;
private Y y;
private Object lockXY = new Object ();
private R r;
private S s;
private Object lockRS = new Object ();
public void do1 ()
{
synchronize (lockXY) {
}
...
}
public void do2 ()
{
synchronize (lockRS) {
}
}
}
Beware to make locking to complex, you may run into dead locks
As in the accepted answer, the object you choose is arbitrary, just make sure you use it correctly. However, some objects are better than others. It's best practice not to use some object that may be accessible outside the context of the locking - if it is some other piece of code may also decide to synchronize on it, or call notify on it or whatever. So preferably use java.util.concurrent instead, or use private objects.
Related
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.
For example I have a class with 2 counters (in multi-threaded environment):
public class MyClass {
private int counter1;
private int counter2;
public synchronized void increment1() {
counter1++;
}
public synchronized void increment2() {
counter2++;
}
}
Theres 2 increment operations not related with each other. But I use same object for lock (this).
It is true that if clients simultaneously calls increment1() and increment2() methods, then increment2 invocation will be blocked until increment1() releases the this monitor?
If it's true, does it mean that I need to provide different monitor locks for each operation (for performance reasons)?
It is true that if clients simultaneously calls increment1() and increment2() methods, then increment2 invocation will be blocked until increment1() releases the this monitor?
If they're called on the same instance, then yes.
If it's true, does it mean that I need to provide different monitor locks for each operation (for performance reasons)?
Only you can know that. We don't know your performance requirements. Is this actually a problem in your real code? Are your real operations long-lasting? Do they occur very frequently? Have you performed any diagnostics to estimate the impact of this? Have you profiled your application to find out how much time is being spent waiting for the monitor at all, let alone when it's unnecessary?
I would actually suggest not synchronizing on this for entirely different reasons. It's already hard enough to reason about threading when you do control everything - but when you don't know everything which can acquire a monitor, you're on a hiding to nothing. When you synchronize on this, it means that any other code which has a reference to your object can also synchronize on the same monitor. For example, a client could use:
synchronized (myClass) {
// Do something entirely different
}
This can lead to deadlocks, performance issues, all kinds of things.
If you use a private final field in your class instead, with an object created just to be a monitor, then you know that the only code acquiring that monitor will be your code.
1) yes it's true that increment1() blocks increment2() and vice versa because they both are implicitly synchronizing on this
2) if you need a better performance consider the lock-free java.util.concurrent.atomic.AtomicInteger class
private AtomicInteger counter1 = new AtomicInteger();
private AtomicInteger counter2 = new AtomicInteger();
public void increment1() {
counter1.getAndIncrement();
}
public void increment2() {
counter2.getAndIncrement();
}
If you synchonize on the method, as what you did here, you lock the whole object, so two thread accessing a different variable from this same object would block each other anyway.
If you want to syncrhonize only a counter at a time so two thread won't block each other while accessing different variables, you have to add the two counters here in two synchronized block, and use different variables as the "lock" of the two blocks.
You are right it will be a performance bottleneck if you use same Object. You can use different lock for individual counter or use java.util.concurrent.atomic.AtomicInteger for concurrent counter.
Like:
public class Counter {
private AtomicInteger count = new AtomicInteger(0);
public void incrementCount() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
Yes the given code is identical to the following:
public void increment1() {
synchronized(this) {
counter1++;
}
}
public oid increment2() {
synchronized(this) {
counter2++;
}
}
which means that only one method can be executed at the same time. You should either provide different locks (and locking on this is a bad idea to begin with), or some other solution. The second one is the one you actually want here: AtomicInteger
Yes if multiple threads try to call methods on your object they will wait trying to get the lock (although the order of who gets the lock isn't guaranteed.) As with everything there is no reason to optimise until you know this is the bottle neck in you code.
If you need the performance benefits that can be had from being able to call both operations in parallel, then yes, you do not to provide different monitor objects for the different operations.
However, there is something to be said for premature optimization and that you should make sure that you need it before making your program more complex to accommodate it.
public class ObjectA {
private void foo() {
MutableObject mo = new MutableObject();
Runnable objectB = new ObjectB(mo);
new Thread(objectB).start();
}
}
public class ObjectB implements Runnable {
private MutableObject mo;
public ObjectB(MutableObject mo) {
this.mo = mo;
}
public void run() {
//read some field from mo
}
}
As you can see from the code sample above, I pass a mutable object to a class that implements Runnable and will use the mutable object in another thread. This is dangerous because ObjectA.foo() can still alter the mutable object's state after starting the new thread. What is the preferred way to ensure thread safety here? Should I make copy of the MutableObject when passing it to ObjectB? Should the mutable object ensure proper synchronization internally? I've come across this many times before, especially when trying to use SwingWorker in a number of GUI applications. I usually try to make sure that ONLY immutable object references are passed to a class that will use them in another thread, but sometimes this can be difficult.
This is a hard question, and the answer, unfortunately, is 'it depends'. You have three choices when it comes to thread-safety of your class:
Make it Immutable, then you don't have to worry. But this isn't what you're asking.
Make it thread-safe. That is, provide enough concurrency control internal to the class that client code doesn't have to worry about concurrent threads modifying the object.
Make it not-thread safe, and force client code to have some kind of external synchronization.
You're essentially asking whether you should use #2 or #3. You are worried about the case where another developer uses the class and doesn't know that it requires external synchronization. I like using the JCIP annotations #ThreadSafe #Immutable #NotThreadSafe as a way to document the concurrency intentions. This isn't bullet-proof, as developers still have to read the documentation, but if everyone on the team understands these annotations and consistently applies them, it does make things clearer.
For your example, if you want to make the class not thread-safe, you could use AtomicReference to make it clear and provide synchronization.
public class ObjectA {
private void foo() {
MutableObject mo = new MutableObject();
Runnable objectB = new ObjectB(new AtomicReference<>( mo ) );
new Thread(objectB).start();
}
}
public class ObjectB implements Runnable {
private AtomicReference<MutableObject> mo;
public ObjectB(AtomicReference<MutableObject> mo) {
this.mo = mo;
}
public void run() {
//read some field from mo
mo.get().readSomeField();
}
}
I think you are overcomplicating it. If it is as the example (a local variable of which no reference is kept) you should trust that nobody will try to write to it. If it is more complicated (A.foo() has more LOC) if possible, create it only to pass to the thread.
new Thread(new MutableObject()).start();
If not (due to initializations), declare it in a block so it gets out of scope immediately, even maybe in a separate private method.
{
MutableObject mo = new MutableObject();
Runnable objectB = new ObjectB(mo);
new Thread(objectB).start();
}
....
Copy the object. You won't have any weird visibility problems because you pass the copy to a new Thread. Thread.start always happens before the new thread enters its run method. If you change this code to pass the object to an existing thread, you need proper synchronization. I recommend a blocking queue from Java.util.concurrent.
Without knowing your exact situation, this question will be difficult to answer precisely. The answer totally depends on what the MutableObject represents, how many other threads may modify it simultaneously, and whether or not the threads that read the object care whether its state changes while they are reading it.
With respect to thread-safety, internally synchronizing all reads and writes to MutableObject is provably the "safest" thing to do, but it comes at the cost of performance. If contention is really high on reads and writes, then your program may suffer performance issues. You can get better performance by sacrificing some guarantees on mutual exclusion - whether those sacrifices are worth the performance increases totally depends on the specific problem you're trying to solve.
You can also play some games with how you go about "internally synchronizing" your MutableObject, if that's what you end up doing. If you haven't already, I'd recommend reading up on the differences between volatile and synchronized and understand how each can be used to ensure thread safety for different situations.
I know the difference between synchronized method and synchronized block but I am not sure about the synchronized block part.
Assuming I have this code
class Test {
private int x=0;
private Object lockObject = new Object();
public void incBlock() {
synchronized(lockObject) {
x++;
}
System.out.println("x="+x);
}
public void incThis() { // same as synchronized method
synchronized(this) {
x++;
}
System.out.println("x="+x);
}
}
In this case what is the difference between using lockObject and using this as the lock? It seems to be the same to me..
When you decide to use synchronized block, how do you decide which object to be the lock?
Personally I almost never lock on "this". I usually lock on a privately held reference which I know that no other code is going to lock on. If you lock on "this" then any other code which knows about your object might choose to lock on it. While it's unlikely to happen, it certainly could do - and could cause deadlocks, or just excessive locking.
There's nothing particularly magical about what you lock on - you can think of it as a token, effectively. Anyone locking with the same token will be trying to acquire the same lock. Unless you want other code to be able to acquire the same lock, use a private variable. I'd also encourage you to make the variable final - I can't remember a situation where I've ever wanted to change a lock variable over the lifetime of an object.
I had this same question when I was reading Java Concurrency In Practice, and I thought I'd add some added perspective on the answers provided by Jon Skeet and spullara.
Here's some example code which will block even the "quick" setValue(int)/getValue() methods while the doStuff(ValueHolder) method executes.
public class ValueHolder {
private int value = 0;
public synchronized void setValue(int v) {
// Or could use a sychronized(this) block...
this.value = 0;
}
public synchronized int getValue() {
return this.value;
}
}
public class MaliciousClass {
public void doStuff(ValueHolder holder) {
synchronized(holder) {
// Do something "expensive" so setter/getter calls are blocked
}
}
}
The downside of using this for synchronization is other classes can synchronize on a reference to your class (not via this, of course). Malicious or unintentional use of the synchronized keyword while locking on your object's reference can cause your class to behave poorly under concurrent usage, as an external class can effectively block your this-synchronized methods and there is nothing you can do (in your class) to prohibit this at runtime. To avoid this potential pitfall, you would synchronize on a private final Object or use the Lock interface in java.util.concurrent.locks.
For this simple example, you could alternately use an AtomicInteger rather than synchronizing the setter/getter.
Item 67 of Effective Java Second Edition is Avoid excessive synchronization, thus I would synchronize on a private lock object.
Every object in Java can act as a monitor. Choosing one is dependent on what granularity you want. Choosing 'this' has the advantage and disadvantage that other classes could also synchronize on the same monitor. My advice though is to avoid using the synchronize keyword directly and instead use constructs from the java.util.concurrency library which are higher level and have well defined semantics. This book has a lot of great advice in it from very notable experts:
Java Concurrency in Practice
http://amzn.com/0321349601
In this case it does not matter which object you choose for lock. But you must consistently use the same object for locking to achieve correct synchronization. Above code does not ensure proper synchronization as you once use the 'this' object as lock and next the 'lockObject' as lock.
What is the difference between a Collections.synchronizedMap() and a wrapper around a HashMap with all the methods synchronized. I dont see any difference becuase Collections.synchronizedMap() internally maintains the same lock for all methods.
Basically, what is the difference between the following code snippets
Class C {
Object o;
public void foo() {
synchronized(o) {
// thread safe code here
}
}
}
and
Class C {
Object o;
public synchronized void foo() {
}
}
There is only one difference:
Collections.synchronizedMap is able to use a different monitor than itself.
Using synchronized methods is the same as using sychnchonized(this)-blocks, which means, the wrapper would be the monitor and could be locked from the outside of the wrapper.
If you doesn't want an outside application to lock your monitor, you need to hide it.
On the other side, if you want to call multiple methods in a thread safe fashion, it is the easiest way to lock the whole collection (but it's not very scaleable, indeed).
Ps: For reuse, it's better to delegate the method calls to a backup-Map than to override the class, because you can switch to another Map implementation later, without changing your wrapper.
Both approaches acquire a monitor on the object and so should perform exactly the same. The main reason for the difference is architectural. The synchronized wrapper allows extending the basic non-thread safe variation easily.
Having said that don't use either, use ConcurrentHashMap. It uses lock striping so it's much quicker to use than either approach (as they are the same in terms of overhead + contention). Lock striping allows segments of the backing array to be locked independently. This means it's less probable that two threads will request to acquire the same lock.
Do not reinvent the wheel and use what is provided by the API.
You should always decorate rather than lumping everything and all feartures into one big featured class.
Always take the plain Map and decorate it with Collections or use a java.util.concurrent and use a real lock, so one can atomically inspect and update the map. Tomorrow you might want to change the Hashtable to a Treemap and you will be in trouble if your stuck with a hashtable.
So, why do you ask? :) Do you really believe that if class is placed in java.util package then some magic happens and its java code works in some tricky way?
It really just wraps all methods with synchronized {} block and nothing more.
UPD: the difference is that you have much less chances to make a mistake if you use synchronized collection instead of doing all synchronization stuff by yourself.
UPD 2: as you can see in sources they use 'mutex'-object as monitor. When you use synchronized modifier in method signature (i.e. synchronized void doSmth()) current instance of your object (i.e. this) is used as a monitor. Two blocks of code below are the same:
1.
synchronized public void doSmth () {
someLogic ();
moreLogic ();
}
synchronized public static void doSmthStatic () {
someStaticLogic ();
moreStaticLogic ();
}
2.
public void doSmth () {
synchronized (this) {
someLogic ();
moreLogic ();
}
}
public static void doSmthStatic () {
synchronized (ClassName.class) {
someStaticLogic ();
moreStaticLogic ();
}
}
If thread safety is the case, use concurrency package data structures. Using the wrapper class will reduce all accesses to the Map into a sequential queue.
a) Threads waiting to do operations at totally different points in the Map will be waiting for the same lock. Based on the number of threads this can affect the application performance.
b) Consider compound operations on the Map. Using a wrapper with a Single lock will not help. For example. "Look if present then add" kind of operations. Thread syncronization will again become an issue.