Java:synchronize关键字不会阻塞不同线程

时间:2016-09-13 10:46:37

标签: java concurrency locking synchronized

public class SynchronizeTest {

    public synchronized void methodA() {
        System.out.println("calling method a ...");
        sleep(2000);
        System.out.println("ending method a");
    }

    public void methodC() {
        System.out.println("calling method C");
        new Thread(new Runnable() {
            @Override
            public void run() {
                methodA();
            }
        }).start();
        sleep(100);
        System.out.println("end method C");
    }

    public static void main(String[] args) {
        new SynchronizeTest().methodC();
    }


    static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

首先,我猜是因为我synchronize方法A,意味着整个对象将被锁定,直到此方法完成。所以答案应该是:

calling method C
calling method a
ending method a
ending method C

但事实证明,结果有点像:

calling method C
calling method A
ending method C
ending method A

这意味着methodA不会像我猜的那样锁定对象。请告诉我原因。

4 个答案:

答案 0 :(得分:2)

在实例方法上使用synchronized关键字时,意味着该对象上的方法只能由一个线程调用。

这并不意味着对所有对象的方法都有任何形式的锁定,即在该方法的调用过程中可以调用其他实例方法 - 当您在进行异步调用时也更容易。

由于您在methodC的线程中调用它,并且methodA中的休眠时间远远大于终止methodC之前的休眠时间,因此您当前的输出很可能是每次都会发生。

以下是相关的文档引用(请参阅第here页):

  

[...]使[...]方法同步有两个效果:

     
      
  • 首先,对同一对象的两次同步方法的调用不可能进行交错。当一个线程正在执行时   对象的同步方法,所有其他调用的线程   同一对象块的同步方法(暂停执行)   直到第一个线程完成对象。

  •   
  • 其次,当同步方法退出时,它会自动建立>与之后发生的关系   调用同一对象的同步方法。这个   保证所有人都可以看到对象状态的变化   线程。

  •   

注意

您可能希望join线程调用methodA,以确保在打印methodC中的最后一个语句之前终止执行。

答案 1 :(得分:1)

首先,你有2个线程1)main和2)你创建(比如说thread1)。现在发生的是你使methodA同步,所以当thread1到达那里它将保留在该方法并尝试完成执行但同时主线程可以进一步处理并打印最后的C语句。因为你在你的方法中添加了sleep调用,这导致thread1睡2秒钟。所以输出将是C(主线程),一个(你的线程),C(主线程),一个(你的线程)

答案 2 :(得分:1)

阅读本文:https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html 正如它所说,同一个对象上的两个同步方法的调用不可能交错。当一个线程正在为对象执行同步方法时,所有其他线程调用同一对象的同步方法(暂停执行)直到第一个线程完成对象。这意味着该对象将被锁定以用于其他同步方法。 同步方法C也不是一个好主意。它将为您提供以下输出:调用方法C /调用方法a /结束方法a /结束方法C. 为了获得所需的输出,您可以使用以下代码:

public class SynchronizeTest implements Runnable{

    public synchronized void methodA() throws InterruptedException {
        System.out.println("calling method a ...");
        Thread.sleep(2000);
        System.out.println("ending method a");
        this.notify();
    }

    public synchronized void methodC() throws InterruptedException {
        System.out.println("calling method C");
        new Thread(new Runnable() {
            @Override
            public void run() {
                methodA();
            }
        }).start();
        this.wait();
        System.out.println("end method C");
    }

    public static void main(String[] args) throws InterruptedException {
        new Test().methodC();
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

    }
}

答案 3 :(得分:0)

关键字synchronized表示发生的错误,不同时发生 线程使用相同的变量,正在被阻止。 锁定一个线程根本就没有意义,因为你可以直接调用一个方法。