Java同步方法

时间:2015-07-27 11:57:54

标签: java android multithreading thread-safety deadlock

考虑以下代码:

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'锁定只能访问此方法或访问此方法中使用的所有对象,则无法找到任何位置。

3 个答案:

答案 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的任何其他方法。