考虑以下代码:
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);
}
}
}
我有一个简单的问题: 当线程1调用onSignalsTimeout方法时,线程2可以访问在该方法中访问的对象吗?
如果'synchronized'锁定只能访问此方法或访问此方法中使用的所有对象,则无法找到任何位置。
答案 0 :(得分:86)
首先,忘记同步方法。一种所谓的同步方法......
synchronized AnyType foobar(...) {
doSomething();
}
只不过是写这篇文章的捷径:
AnyType foobar(...) {
synchronized(this) {
doSomething();
}
}
在任何一种情况下,方法都没有什么特别之处。有意义的是同步块,同步块的作用非常简单。当JVM执行此操作时:
synchronized(foo) {
doSomething();
}
首先评估表达式foo
。结果必须是对象引用。然后它锁定对象,执行synchronized
块的主体,然后解锁对象。
但锁定意味着什么?这可能意味着比你想象的要少。 不阻止其他线程使用该对象。它不会阻止它们访问对象的字段,也不会阻止它们更新其字段。锁定对象唯一阻止的是,它可以防止其他线程同时锁定同一个对象。
如果线程A尝试输入synchronized(foo) {...}
而线程B已经锁定了foo(在同一个synchronized
块中,或者在另一个块中),则线程A将被强制等待直到线程B释放锁。
您使用synchronized
块来保护数据。
假设您的程序有一些可以处于不同状态的对象集合。假设某些状态有意义,但还有其他状态没有意义 - 无效的状态。
假设在没有临时创建无效状态的情况下,线程无法将数据从一个有效状态更改为另一个有效状态。
如果您将更改状态的代码放在synchronized(foo)
块中,并将可以看到状态的每个代码块放入同步阻止同一对象,foo
的块,然后您将阻止其他线程看到临时无效状态。
答案 1 :(得分:8)
是的,其他线程可以访问方法中使用的对象; synchronized关键字保证当时只有一个线程可以执行该方法的代码。
来自https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html:
- 首先,对同一对象的两个同步方法的调用不可能进行交错。当一个线程正在执行时 对象的同步方法,所有其他调用的线程 同一对象块的同步方法(暂停执行) 直到第一个线程完成对象。
- 其次,当同步方法退出时,它会自动建立与之后的任何关系 调用同一对象的同步方法。这个 保证所有人都可以看到对象状态的变化 线程。请注意,构造函数无法同步 - 使用 synchronized关键字与构造函数是语法错误。 同步构造函数没有意义,因为只有线程 创建一个对象应该有权访问它 构成。
答案 2 :(得分:5)
在此上下文中,synchronized
同时锁定此方法以及类中标记为synchronized
的任何其他方法。