线程获得级别

时间:2012-08-21 22:35:44

标签: java multithreading synchronization synchronized

我不清楚

的概念
  

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(),因为整个类都被锁定了?

4 个答案:

答案 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。由于classjava.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
}

其中monitorentermonitorexit分别为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个对象,counter1counter2,则1个线程正在调用counter1.getCount(),而另一个正在调用counter2.getCount()时间,然后他们将锁定相同​​的Class对象,一个将阻止另一个。

但如果2个主题是调用counter1.setCount(...)counter2.setCount(),则他们将分别锁定不同的对象 - counter1counter2。他们不会互相阻挡。

如上所述,在你的setter和getter上存在不对称是非常糟糕的形式,而且static是不寻常的。

  

这是否意味着当getCount()被调用时,另一个线程无法访问setCount(),因为整个类都被锁定了?

没有。如果调用getCount()Counter.class将被锁定,并且setCount(...)被调用counter1counter2被锁定。锁定线程的唯一时间是同一对象已被另一个线程锁定。仅仅因为Counter.class上存在锁定,而不是意味着存在某种超级类锁定。阻止另一个线程的唯一时间是它是否也锁定了Counter.class

我花点时间阅读Sun的great documentation on how synchronized works