java多线程中实例上获取的锁

发布于 2024-10-18 13:22:12 字数 211 浏览 2 评论 0原文

我读到java中的锁是在实例(对象)的基础上获得的(在实例方法的情况下)
还可以在类的对象上获取锁(在静态方法的情况下)。

但我想知道特定对象一次可以获得多少个锁

一个对象可以同时拥有多个锁吗?
如果是,请举例说明。

请帮助我理清我的概念。

I read that the locks in java are obtained on the instance(object) basis (in case of instance method)
Also the locks can be obtained 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

放肆 2024-10-25 13:22:12

每个同步块仅适用于一个对象。对象不会拥有锁。它是锁定对象以对其进行操作的执行线程。

锁总是在对象上获得。例如下面是可以获得锁的两个实例。第一个锁定类(对象)的实例。

Object obj = new Object();

synchronized(obj) {
    workOnIt(obj);
}

第二个看起来像是锁定了一个班级。但 Test.class 是我的 Test 类的 java.lang.Class 实例的特殊表示。

synchronized(Test.class) {
    // call some static method here
}

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
}
抹茶夏天i‖ 2024-10-25 13:22:12

一个线程可以持有多个对象的多个锁。但你必须自己承担风险(以避免死锁或性能下降)

synchronized (obj1)
{
  synchronized (obj2)
  {
    // do sth. against obj1 and obj2 
  }
}

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 
  }
}
梦与时光遇 2024-10-25 13:22:12

锁(以同步块或方法的形式)有一个主要作用:同时只有一个线程可以进入该对象的同步块/方法,即只有一个线程可以是该锁的所有者(或“监视器”,正如 JLS 中所称的那样)。

(另一个效果是,当一个同步块内(或之前)更改的所有变量位于同一监视器上的后续同步块中(或之后)时,保证在其他线程中可见。)

您正在使用多少个对象/变量在此块中,是您的自由决定,但通常您对以某种方式组合在一起的所有数据使用一把锁,并且不应独立修改/访问。

请注意,在对象上拥有锁本身并不能避免其他线程更改/使用该对象,它只是避免其他线程在该对象上同步。所以一定要同步所有相关的方法(并且不要有公共变量)。

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).

情愿 2024-10-25 13:22:12

考虑带有同步块的方法(改编自 JVMS

public void foo(Object f) {
  synchronized(f) {
    doSomething();
  }
}

让我们将其翻译为伪代码(Java 和字节代码的混合!!!):

public void foo(Object f) {
  monitorenter(f);
  try {
    doSomething();
    monitorexit(f);
  } catch(Throwable e) {
    monitorexit(f);
    throw e;
  }
}

这就是它的样子,如果字节码指令 < code>monitorenter 和 monitorexit 是 java 方法。

每个对象都有一个监视器。如果一个线程进入监视器并且监视器未被获取(锁定、获取),那么它会获取(锁定、获取)监视器并调用 doSomething()(这是下一行)。

如果现在有第二个线程出现并尝试进入对象 f 上的监视器,那么它会在此位置等待,直到对象 f 上的监视器被释放。当第一个线程调用两个 monitorexit 指令(字节码!!)之一时,监视器被释放。

回到问题 - 一个线程可以输入多少个监视器?可能没有限制(堆栈大小限制除外)。如果doSomething是另一个同步方法并且使用对象g的监视器,那么线程一也将进入该监视器并获取g上的监视器(如果有的话)。

它不是获取锁的对象,而是进入对象监视器的线程,并且该进程正在“锁定”。

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".

扛刀软妹 2024-10-25 13:22:12

当您使用静态方法获取类上的锁时,您将像其他任何对象一样获取对象上的锁。

class A {
    synchronized void foo() { 
        // do something.
    }

    static synchronized void bar() { 
        // do something.
    }
}

基本上与 相同

class A {
    void foo() { 
        Object locked = this;
        synchronized(locked) {
            // do something.
        }
    }

    static void bar() { 
        Object locked = A.this;
        synchronized(locked) {
            // do something.
        }
    }
}

唯一可能因其拥有的锁数量而令人困惑的类是 Lock 的实例。这是一种不同风格的锁,但也是一个对象,因此也有一个标准锁。所以你可以

Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();

但是,你可以令人困惑

Lock lock = new ReentrantLock();
synchronized(lock) { // don't do this.
   lock.wait(); // argh.
}

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.
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文