繁体   English   中英

Java:synchronize关键字不会阻止其他线程上的对象

[英]Java: synchronize keyword doesn't block object on different thread

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不会像我猜的那样锁定对象。 请告诉我为什么。

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

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

既然你是你的线程内调用它methodC ,并在睡眠时间methodA比结束前的一个更大的methodC ,您的电流输出是非常可能发生的每一次。

这是相关的文档报价(请参阅此处的页面):

使得方法同步具有两个作用:

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

  • 其次,当同步方法退出时,它会自动建立与先后发生的关系,并随后对同一对象调用同步方法。 这保证了对象状态的更改对所有线程都是可见的。

注意

您可能需要join调用methodA的线程,以确保在执行methodC的最后一条语句之前终止其执行。

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

请阅读以下内容: https : //docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html如前所述,不可能对同一对象的两次同步方法调用进行交织。 当一个线程正在执行对象的同步方法时,所有其他调用同一对象块的同步方法的线程(挂起执行),直到第一个线程对该对象完成。 这意味着该对象将被其他同步方法锁定。 同步methodC也不是一个好主意。 它将为您提供以下输出:调用方法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

    }
}

关键字synchronized意味着防止不同线程使用相同变量时发生的错误。 锁定线程根本没有任何意义,因为您可以随后调用方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM