简体   繁体   English

同步方法和块的行为不同

[英]Behavior of synchronized method and block is different

I observed a scenario where use of synchronized method or synchronized block producing different results. 我观察到了使用同步方法或同步块产生不同结果的情况。 From below code: 从下面的代码:

class Callme {
    void call(String msg) {
        System.out.print("[" + msg);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("]");
    }       
}

class Caller implements Runnable{
    String msg;
    Callme target;
    Thread t;

    public Caller(Callme target, String msg) {
        this.target = target;
        this.msg = msg;
        t = new Thread(this, "Caller thread");
        t.start();
    }

    @Override
    public void run() {
        synchronized(target) {
            target.call(msg);
            new Callme().call(msg);
        }
    }

}

public class Test {

    public static void main(String[] args) throws InterruptedException {
        Callme obj = new Callme();

        new Caller(obj, "thread1");
        new Caller(obj, "thread2");
        new Caller(obj, "thread3");

        Thread.currentThread().join();
    }
}

When I use the synchronized block in the Caller::run method the ouput is synchronized as below: 当我在Caller :: run方法中使用同步块时,输出将如下同步:

[thread1]
[thread1]
[thread3]
[thread3]
[thread2]
[thread2]

But when I use the synchronized method for the Callme::call method, instead of synchronized block, the output is not synchronized: 但是,当我对Callme :: call方法使用同步方法而不是同步块时,输出将不同步:

[thread1]
[thread1[thread2]
]
[thread3[thread2]
]
[thread3]

My Expectation is the output should not be synchronized on both cases because I am using different objects when calling the "Callme::call" method 我的期望是两种情况下的输出均不应同步,因为调用“ Callme :: call”方法时我使用的对象不同

This made me question my understanding of the Synchronized block concept? 这使我质疑我对同步块概念的理解?

A synchronized method is equivalent to a synchronized(this) -block for the length of the entire method, however your code is using synchronized(target) , and target is a shared instance of Callme . 在整个方法的长度上,同步方法等效于sync synchronized(this) -block,但是您的代码正在使用Callme synchronized(target) ,而targetCallme的共享实例。 In other words: the object being synchronized on is different, so the behavior is not the same. 换句话说:同步对象是不同的,因此行为是不相同的。

In the case you use synchronized(target) , it means that all threads synchronize on the same instance of Callme so their behavior is serial: a thread will hold the monitor of that Callme instance for the whole duration of the Caller.run method, so in effect the threads are executed one after the other. 如果您使用Callme synchronized(target) ,则意味着所有线程都在同一个Callme实例上同步,因此它们的行为是串行的:一个线程将在Caller.run方法的整个过程中保留该Callme实例的监视器。实际上,线程是一个接一个地执行的。

In the case of a synchronized method, the threads each synchronize on their own instance of Caller , so in effect there is no serialization (except for the writes to System.out ). 在使用同步方法的情况下,每个线程都在自己的Caller实例上进行同步,因此实际上没有序列化(对System.out的写操作除外)。

Some additional remarks: 一些补充说明:

  • Calling Thread.currentThread().join() is a bad idea, because it will wait on itself 调用Thread.currentThread().join()是一个坏主意,因为它会等待自己
  • In general don't create and start Thread instances in the Runnable implementation that is going to be run by that thread: you lose access to the thread. 通常,不要在将要由该线程运行的Runnable实现中创建和启动Thread实例:您将无法访问该线程。 Especially don't do this in the constructor, because you are publishing a partially constructed object to the Thread , which is not a big problem in this code, but might lead to subtle bugs in more complex applications. 尤其不要在构造函数中执行此操作,因为要将部分构造的对象发布到Thread ,这在代码中不是什么大问题,但可能会导致更复杂的应用程序中出现细微的错误。

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

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