Java 同步方法

Java synchronized method

考虑这段代码:

public synchronized void onSignalsTimeout(List<SignalSpec> specs) {
    if (specs != null && specs.size() > 0) {
        for (SignalSpec spec : specs) {
            ParsedCANSignal timeoutedSignal = new ParsedCANSignal();
            SignalsProvider.getInstance().setSignal(spec.name, spec.parent.parent.channel, timeoutedSignal);
        }
    }
}

我有一个简单的问题: Thread 1调用onSignalsTimeout方法时,Thread 2是否可以访问该方法中访问的对象?

如果 'synchronized' 仅锁定对该方法的访问或对该方法中使用的所有对象的访问,则找不到任何地方。

在此上下文中,synchronized 同时锁定此方法以及在您的 class.

中类似地标记为 synchronized 的任何其他方法

是的,其他线程可以访问该方法中使用的对象; synchronized 关键字保证同一时间不超过一个线程可以执行该方法的代码。

来自https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

  • 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 that constructors cannot be synchronized — using the synchronized keyword with a constructor is a syntax error. Synchronizing constructors doesn't make sense, because only the thread that creates an object should have access to it while it is being constructed.

首先,忘记同步方法。一个所谓的同步方法...

synchronized AnyType foobar(...) {
    doSomething();
}

不过是写这个的捷径:

AnyType foobar(...) {
    synchronized(this) {
        doSomething();
    }
}

在任何一种情况下,方法都没有什么特别之处。比较特别的是synchronizedblock,一个synchronized块做的事情很简单。当 JVM 执行此操作时:

synchronized(foo) {
    doSomething();
}

它首先计算表达式foo。结果必须是对象引用。然后锁定对象,执行 synchronized 块的主体,然后解锁对象。

但是 locked 是什么意思?这可能意味着比你想象的要少。它不会 阻止其他线程使用该对象。它不会阻止他们访问对象的字段或更新其字段。锁定对象唯一可以防止的是,它可以防止其他线程同时锁定同一个对象。

如果线程 A 试图进入 synchronized(foo) {...} 而线程 B 已经锁定了 foo(在同一个 synchronized 块中,或者在不同的块中),那么线程 A 将被迫等待直到线程 B 释放锁。


您使用 synchronized 个块来保护 数据

假设您的程序有一些可以处于不同状态 的对象集合。假设一些状态有意义,但还有其他状态没有意义——无效个状态。

假设如果不临时创建无效状态,线程不可能将数据从一个有效状态更改为另一个有效状态。

如果你把改变状态的代码放在一个synchronized(foo)块中,然后你把每个个代码块放在see 状态进入同步块,锁定 同一个对象 foo,然后你将防止其他线程看到临时无效状态。