Locks obtained on instances in java multithreading
I read that the locks in java are obtained on the instance(object) basis (in case of instance method)
Also the locks can be obtaine开发者_运维知识库d on the object of class (in case of static method).But I wondered how many locks can be obtained at a time by a particular object?
Can an object possess more than one lock at a time ?
If yes, please explain with an example.Please help me clear my concept.
Only on one object per synchronized block. Objects won't possess the locks. It is the thread of execution which locks an object for working on it.
Locks are always obtained on objects. For example the below are two instances where locks can be obtained. The first one locks on an instance of a class (object).
Object obj = new Object();
synchronized(obj) {
workOnIt(obj);
}
The second one looks like it locks on a class. But Test.class is a special representation for the java.lang.Class instance of my Test class.
synchronized(Test.class) {
// call some static method here
}
One thread can hold multiple locks to multiple objects. But you have to take your own risk (to avoid dead lock or performance degrade)
synchronized (obj1)
{
synchronized (obj2)
{
// do sth. against obj1 and obj2
}
}
A lock (in the form of a synchronized block or method) has one primary effect: Only one thread at the same time can enter an synchronized block/method of this object, i.e. only one thread can be the owner of this lock (or "monitor", as it is called in the JLS).
(Another effect is that all variables changed inside (or before) one synchronized block is guaranteed to be visible in other threads when they are in (or after) a later synchronized block on the same monitor.)
How many objects/variables you are using in this block, is your free decision, but usually you use one lock for all data that is somehow together, and should not be modified/accessed independently.
Note that having a lock on an object does not by itself avoids changing/using of this object by other threads, it only avoids other threads synchronizing on this object. So be sure to synchronize all relevant methods (and do not have public variables).
Consider a method with a synchronized block (adapted from JVMS)
public void foo(Object f) {
synchronized(f) {
doSomething();
}
}
Let's translate it to pseudocode (a mixture of Java and byte code!!!):
public void foo(Object f) {
monitorenter(f);
try {
doSomething();
monitorexit(f);
} catch(Throwable e) {
monitorexit(f);
throw e;
}
}
This is how it would look like, if the bytecode instruction monitorenter
and monitorexit
were java methods.
Each object has one monitor. If one thread enters the monitor and the monitor is not acquired (locked, obtained), than it acquires (locks, obtains) the monitor and calls doSomething()
(which is the next line).
If now a second thread comes along and tries to enter the monitor on object f
, then it waits at this place until the monitor on object f
is released. The monitor is released when the first thread calls one of the two monitorexit
instructions (bytecode!!).
Back to the question - how many monitors can be entered by one thread? There may be no limit (except for stack size limits). If doSomething
is another synchronized method and uses a monitor of Object g
, then thread one will enter that monitor too and obtain the monitor on g
(if available).
It's not an object that obtains a lock, it's a thread that enters an objects monitor, and that process is "locking".
When you obtain a lock on a Class with a static method, you are obtain a lock on an object just like any other.
class A {
synchronized void foo() {
// do something.
}
static synchronized void bar() {
// do something.
}
}
is basically the same as
class A {
void foo() {
Object locked = this;
synchronized(locked) {
// do something.
}
}
static void bar() {
Object locked = A.this;
synchronized(locked) {
// do something.
}
}
}
The only class which can be confusing for the number of locks it has are instance of a Lock
. This is a different style of Lock, but is also an Object so has a standard lock as well. So you can
Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();
however, you can confusingly
Lock lock = new ReentrantLock();
synchronized(lock) { // don't do this.
lock.wait(); // argh.
}
精彩评论