繁体   English   中英

同步方法和块的行为不同

[英]Behavior of synchronized method and block is different

我观察到了使用同步方法或同步块产生不同结果的情况。 从下面的代码:

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

当我在Caller :: run方法中使用同步块时,输出将如下同步:

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

但是,当我对Callme :: call方法使用同步方法而不是同步块时,输出将不同步:

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

我的期望是两种情况下的输出均不应同步,因为调用“ Callme :: call”方法时我使用的对象不同

这使我质疑我对同步块概念的理解?

在整个方法的长度上,同步方法等效于sync synchronized(this) -block,但是您的代码正在使用Callme synchronized(target) ,而targetCallme的共享实例。 换句话说:同步对象是不同的,因此行为是不相同的。

如果您使用Callme synchronized(target) ,则意味着所有线程都在同一个Callme实例上同步,因此它们的行为是串行的:一个线程将在Caller.run方法的整个过程中保留该Callme实例的监视器。实际上,线程是一个接一个地执行的。

在使用同步方法的情况下,每个线程都在自己的Caller实例上进行同步,因此实际上没有序列化(对System.out的写操作除外)。

一些补充说明:

  • 调用Thread.currentThread().join()是一个坏主意,因为它会等待自己
  • 通常,不要在将要由该线程运行的Runnable实现中创建和启动Thread实例:您将无法访问该线程。 尤其不要在构造函数中执行此操作,因为要将部分构造的对象发布到Thread ,这在代码中不是什么大问题,但可能会导致更复杂的应用程序中出现细微的错误。

暂无
暂无

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

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