33

我在一个类中有 4 个方法( 、 和m1m2。方法和是方法。另外,我有 4 个线程, ,和。m3m4m1m2m3synchronizedt1t2t3t4

如果t1访问m1方法(同步方法),是否可以同时t2线程访问m2方法(同步方法)?如果不是,t2 的状态是什么?

4

4 回答 4

47

如果t1访问m1方法(同步方法),t2线程可以同时访问m2方法(同步方法)吗?

synchronized关键字适用于对象级别,并且只有一个线程可以持有对象的锁。所以只要你说的是同一个对象,那么不会t2会等待t1释放它进入时获取的锁m1

但是,线程可以通过调用Object.wait().

如果不是, t2 的状态是什么?

它会紧紧地等待t1释放锁(从方法返回或调用Object.wait())。具体来说,它将处于一个BLOCKED状态

线程阻塞等待监视器锁的线程状态。处于阻塞状态的线程正在等待监视器锁进入同步块/方法或调用后重新进入同步块/方法Object.wait

示例代码:

public class Test {

    public synchronized void m1() {
        try { Thread.sleep(2000); }
        catch (InterruptedException ie) {}
    }

    public synchronized void m2() {
        try { Thread.sleep(2000); }
        catch (InterruptedException ie) {}
    }

    public static void main(String[] args) throws InterruptedException {
        final Test t = new Test();
        Thread t1 = new Thread() { public void run() { t.m1(); } };
        Thread t2 = new Thread() { public void run() { t.m2(); } };

        t1.start();
        Thread.sleep(500);

        t2.start();
        Thread.sleep(500);

        System.out.println(t2.getState());
    }
}

输出:

BLOCKED
于 2010-07-01T17:08:37.167 回答
11

如果这些方法在同一个监视器上同步,那么它们就不能在不同的线程中同时执行。当第二个线程到达监视器入口时(在这种情况下是同步方法的开始),它将阻塞,直到第一个线程释放监视器。

在这种情况下,阻塞线程的实际状态,由 jconsole 报告,将类似于java.lang.Thread.State: WAITING (on object monitor)

假设所有方法都是普通的实例方法,那么当在同一个对象上调用时它们将共享同一个监视器。也就是说,如果你有类似的东西:

// Thread 1
A a1 = new A();
a1.m1();

// Thread 2
A a2 = new A();
a2.m2()

那么在这种情况下,第二个线程将能够调用该方法,因为它正在尝试获取对象的隐式监视器,该a2对象没有被线程1锁定。但是如果线程2试图调用a1.m2(),那么它将阻塞直到线程1 已完成执行m1()

如果您有静态方法,那么它们会获得类本身的显式监视器(A.class在我的假设命名情况下),因此不会被任何实例方法调用阻塞。

于 2010-07-01T17:08:59.963 回答
4

不,它不能。这是唯一的一点synchronized:不同的线程不能同时做这些事情(你不必防止同一个线程同时做这些事情,因为单个线程根本不能并行做任何事情。)状态等待线程是“等待锁定”。(使用足够现代的 JVM,如果您以正确的方式询问,您实际上可以在控制台上显示此状态。)

于 2010-07-01T17:10:03.503 回答
1

如果t1访问m1方法(同步方法),t2线程可以同时访问m2方法(同步方法)吗?

不会。线程 t2 将等待线程 t1 释放锁。在您的同一个示例中, t2 可以访问未同步的方法 m4 。

同步 方法中的锁

每个对象都有一个与之关联的内在锁。按照惯例,需要对对象的字段进行排他和一致访问的线程必须在访问对象之前获取对象的内在锁,然后在完成后释放内在锁

当线程调用同步方法时,它会自动获取该方法对象的内在锁,并在方法返回时释放它。即使返回是由未捕获的异常引起的,也会发生锁定释放

回到你的第二个查询:

如果不是, t2 的状态是什么?

线程 t2 处于阻塞状态,等待线程 t1 释放锁。

从java文档 页面:

制作synchronized方法有两个作用。

首先,同一对象上的同步方法的两次调用不可能交错。当一个线程正在为一个对象执行同步方法时,所有其他为同一对象调用同步方法的线程都会阻塞(暂停执行),直到第一个线程处理完该对象。

其次,当同步方法退出时,它会自动与任何后续对同一对象的同步方法调用建立起之前的关系。这保证了对对象状态的更改对所有线程都是可见的

于 2016-02-17T14:41:52.723 回答