简体   繁体   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();
        }
    }
}

At first, I guess because I synchronize method A, meaning that whole object will be locked until this method is finished. 起初,我猜是因为我synchronize方法A,这意味着整个对象将被锁定,直到该方法完成为止。 So the answer should be: 所以答案应该是:

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

But turn out, the result something likes: 但是事实证明,结果是这样的:

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

That means methodA doesn't lock object as I guess. 这意味着methodA不会像我猜的那样锁定对象。 Please tell me why. 请告诉我为什么。

When you use the synchronized keyword on an instance method, it means that method on that object can be only invoked by one thread at the time. 在实例方法上使用synchronized关键字时,这意味着该对象上的方法当时只能由一个线程调用。

That doesn't imply any form of locking on all the object's methods, ie other instance methods can be invoked during that method's invocation - easier too when you invoke it asynchronously as you're doing. 这并不意味着对对象的所有方法进行任何形式的锁定,即可以在该方法的调用期间调用其他实例方法-当您在执行操作时异步调用它时,也更容易。

Since you're invoking it within your thread in methodC , and the sleeping time in methodA is much larger than the one before terminating methodC , your current output is very likely to happen every time. 既然你是你的线程内调用它methodC ,并在睡眠时间methodA比结束前的一个更大的methodC ,您的电流输出是非常可能发生的每一次。

Here's the relevant doc quote (see page here ): 这是相关的文档报价(请参阅此处的页面):

[...]making [...] methods synchronized has two effects: 使得方法同步具有两个作用:

  • First, it is not possible for two invocations of synchronized methods >on the same object to interleave. 首先,不可能在同一对象上两次调用同步方法。 When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object. 当一个线程正在执行对象的同步方法时,所有其他调用同一对象块的同步方法的线程(挂起执行),直到第一个线程对该对象完成。

  • Second, when a synchronized method exits, it automatically establishes > a happens-before relationship with any subsequent invocation of a synchronized method for the same object. 其次,当同步方法退出时,它会自动建立与先后发生的关系,并随后对同一对象调用同步方法。 This guarantees that changes to the state of the object are visible to all threads. 这保证了对象状态的更改对所有线程都是可见的。

Note 注意

You may want to join the thread invoking methodA , in order to ensure its execution is terminated before printing the last statement in methodC . 您可能需要join调用methodA的线程,以确保在执行methodC的最后一条语句之前终止其执行。

First of all here you have 2 thread 1) main and 2) that you create(lets say thread1). 首先,您有2个线程1)main和2)您创建的线程(假设为thread1)。 now what happens is you make methodA synchronize so when thread1 reaches there it will remain in that method and try to complete execution but at the same time main thread can process further and print last C statement.because you added sleep call in your method which causes thread1 to sleep for 2 second. 现在发生的事情是使methodA同步,因此当线程1到达那里时它将保留在该方法中并尝试完成执行,但同时主线程可以进一步处理并打印最后的C语句。因为您在方法中添加了sleep调用,这导致thread1睡眠2秒。 so out put will be C(main thread) , a(your thread) , C(main thread) , a(your thread) 所以输出将是C(主线程),a(您的线程),C(主线程),a(您的线程)

Read this: https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html As it says, it is not possible for two invocations of synchronized methods on the same object to interleave. 请阅读以下内容: https : //docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html如前所述,不可能对同一对象的两次同步方法调用进行交织。 When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object. 当一个线程正在执行对象的同步方法时,所有其他调用同一对象块的同步方法的线程(挂起执行),直到第一个线程对该对象完成。 It means that the object will be locked for other synchronized methods. 这意味着该对象将被其他同步方法锁定。 Synchronizing methodC too isn't a good idea either. 同步methodC也不是一个好主意。 It will give you the following output: calling method C / calling method a / ending method a / ending method C. In order to get the output you want, you can use the following code: 它将为您提供以下输出:调用方法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

    }
}

The keyword synchronized means, that errors that occur, when different threads use the same variables, are being prevented. 关键字synchronized意味着防止不同线程使用相同变量时发生的错误。 Locking a thread would make no sense at all, ever since you could just call a method then instead. 锁定线程根本没有任何意义,因为您可以随后调用方法。

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

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