我不清楚
的概念Java Thread在进入实例同步java方法时获取对象级锁定,并在进入静态同步java方法时获取类级别锁。
当它说对象级别锁定和类级别锁定时它是什么意思?
例如:
public class Counter{
private static int count = 0;
private int count2 = 0;
public static synchronized int getCount(){
return count;
}
public synchronized setCount(int count2){
this.count2 = count2;
}
}
getCount()这里将锁定Counter.class对象,而setCount()将锁定当前对象(this)。 此 指的是什么?这是否意味着当getCount()被调用时,另一个线程无法访问setCount(),因为整个类都被锁定了?
答案 0 :(得分:1)
在Java中,每个类和每个类的实例都赋予其内部锁。这些是在进入和退出synchronized
方法时获取和释放的锁。
像往常一样this
指的是调用setCount()
的实例,并且因为每个实例都有自己的内部锁,所以只要调用setCount()
,第二次调用就不会阻塞在您的类的另一个实例上,但尝试在正在进行另一个setCount()
调用的实例上调用setCount()
将阻止。
类锁和实例锁是不同的,因此getCount()
和setCount()
永远不会彼此相互接触。
答案 1 :(得分:1)
static
成员与该类关联,而不是与特定实例关联。因此,static
成员上的同步有效地在整个类上同步,因为静态是类成员
实例成员与类的实例相关联(例如,内部this
锁定),因此如果您在成员字段(非静态)或this
上进行同步,那么您将拥有与之关联的锁定一个实例对象。
在您的示例中,getCount
在类的intrinsik锁上进行同步。你有效地做了:
public setCount(int count){
synchronized(this){
this.count = count;
}
}
如果您这样做,您将在课程级别进行同步:
static Object count = new Object();
synchronized(count){
}
答案 2 :(得分:1)
Java中的每个对象都有一个mutex。由于class
由java.lang.Class
类型的对象表示,因此每个类也都有一个互斥锁。 synchronized
实例方法锁定实例的互斥锁,而synchronized static
方法锁定相应java.lang.Class
实例的互斥锁。
class C {
synchronized T myMethod() { ... }
static synchronized T myStaticMethod() { ... }
}
相当于
class C {
T myMethod() {
synchronized (this) { ... } // An object level lock.
}
static T myStaticMethod() {
synchronized (C.class) { ... } // A class level lock
// is really just an object level lock an a Class.
}
}
一旦您知道要同步的对象,就可以通过将其分解来理解synchronized
关键字。
synchronized (x) {
body();
}
执行
monitorenter(x); // locks x or throws NullPointerException if x is null.
try {
body();
} finally {
monitorexit(x); // unlocks x
}
其中monitorenter
和monitorexit
分别为Java bytecode instructions阻塞,直到获取互斥锁,然后释放互斥锁。
由于synchronized
引入了“受保护区域”,如try ... finally
,即使引发异常,锁也会被释放,但killing the thread会使锁未释放,可能导致{ {3}}
答案 3 :(得分:1)
当它说对象级别锁定和类级别锁定时它是什么意思?
当您锁定static
方法时,您锁定了Class
对象本身,其中每个ClassLoader
都有一个。在您的示例中,
public static synchronized int getCount(){
这是锁定在Counter.class
对象上,与以下内容相同:
public static int getCount() {
synchronized (Counter.class) {
}
如果您改为锁定 not static
的方法,那么您将锁定拥有该方法的对象的实例。在您的示例中:
public synchronized void setCount(int count){
这与锁定特定Counter
实例相同,相当于:
public void setCount(int count){
synchronized (this) {
...
因此,如果您有2个Counter
个对象,counter1
和counter2
,则1个线程正在调用counter1.getCount()
,而另一个正在调用counter2.getCount()
时间,然后他们将锁定相同的Class
对象,一个将阻止另一个。
但如果2个主题是调用counter1.setCount(...)
和counter2.setCount()
,则他们将分别锁定不同的对象 - counter1
和counter2
。他们不会互相阻挡。
如上所述,在你的setter和getter上存在不对称是非常糟糕的形式,而且static
是不寻常的。
这是否意味着当getCount()被调用时,另一个线程无法访问setCount(),因为整个类都被锁定了?
没有。如果调用getCount()
,Counter.class
将被锁定,并且setCount(...)
被调用counter1
或counter2
被锁定。锁定线程的唯一时间是同一对象已被另一个线程锁定。仅仅因为Counter.class
上存在锁定,而不是意味着存在某种超级类锁定。阻止另一个线程的唯一时间是它是否也锁定了Counter.class
。
我花点时间阅读Sun的great documentation on how synchronized
works。