同时执行两个同步方法

问题描述:

我有4种方法(m1,m2,m3m4)在一个类中。方法m1,m2m3是​​方法。另外,我有4个线程分别为t1t2,t3t4同时执行两个同步方法

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

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

的​​关键字适用于对象级别,只有一个线程可持有对象的锁。所以只要你在谈论同一个对象,那么t2将等待t1释放当它进入m1时获得的锁定。

但是,线程可以通过调用Object.wait()来释放锁而无需从方法返回。

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

这将稳坐,等待t1(从方法返回或调用Object.wait())解除锁定。具体来说,它将在BLOCKED state

线程阻塞等待监视器锁定的线程状态。处于阻塞状态的线程正在等待监视器锁定,以便在调用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 
+0

但是如果我们做这样的事情,那又怎样? final Test tt1 = new Test(); final Test tt2 = new Test();线程t1 = new Thread(){public void run(){tt1.m1(); }};线程t2 = new Thread(){public void run(){tt2.m2(); }}; – Prem 2012-04-10 09:17:50

+0

我运行同样的东西,我得到TIMED_WAIT作为输出.... – Prem 2012-04-10 09:18:12

+0

@aioobe在同步代码块(而不是方法)的情况下会发生什么。两个线程可以同时访问同一对象的两个不同的同步代码块吗? – yuva 2014-09-18 11:48:15

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

在这种情况下,被阻塞的线程的实际状态,所报告的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在我假想命名的情况下)显式显示器,所以不会受到任何例如方法调用被阻止。

+0

实际上,它将处于BLOCKED状态,而不是WAITING状态。 – aioobe 2010-07-01 17:19:19

+0

在上面的例子中调用'a2.m2()'有点令人误解。由于'a1'和'a2'是类'A'的不同实例,每个都有自己的'lock'。因此,即使'a1.m1()'和'a2.m1()'也可以同时执行。 – derenio 2015-11-25 10:24:08

+0

@derenio - 那是我在该部分所做的全部观点,根据之前的粗体陈述。因为问题是问是否可以立即调用'm1'和'm2',这就是我在示例中坚持的内容。 – 2015-11-25 10:31:06

不,它不能。这是​​唯一的一点:不同的线程不能同时做这些事情(你不必同时做同一个线程,因为一个线程根本无法并行执行任何操作)。等待线程的状态是'等待锁定'。 (有足够的现代JVM你其实可以有控制台上显示这种状态下,如果你以正确的方式问。)

如果T1接入M1方法(synchronized方法),可以t2的线程访问M2方法(同步方法)同时?

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

锁在synchronized方法

每个对象都有一个与之关联的内部锁。按照惯例,需要独占且一致地访问对象字段的线程在访问它们之前必须获取对象的内部锁,然后在完成对象的内部锁之后释放固有锁

当线程调用同步方法时,自动获取该方法对象的内部锁并在方法返回时释放它。锁定解除即使返回被一个未捕获的异常

回来到您的第二个查询导致发生:

如果不是这样,这将是T2的状态?

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

从Java documentation页:

使​​方法有两个作用。

首先,对同一对象上的同步方法的两次调用是不可能交错的。当一个线程正在执行一个对象的同步方法时,所有其他线程调用同一对象的同步方法块(挂起执行),直到第一个线程完成对象。其次,当一个同步方法退出时,它会自动建立一个与先前关联的同步对象的任何后续调用同步方法。这保证了所有线程都可以看到对象状态的变化