【问题标题】:Android: synchronized() inside constructor has no effect?Android:构造函数内部的同步()没有效果?
【发布时间】:2013-02-24 09:11:54
【问题描述】:

我尝试搜索这个问题,但没有找到任何东西,好像我是唯一一个尝试过的人。

基本上我有一个静态对象,用于在包含类的构造函数中同步资源访问,但我不时注意到它不起作用!

private static Integer              lock = Integer.valueOf(0);

public testClass(Context ctx)
{
    if (ctx != null)
        context = ctx.getApplicationContext();
    else
        context = null;

    synchronized(lock)
    {
        Log.v(at_data.TAG, "I_AM_IN=" + I_AM_IN);
        I_AM_IN = true;

      // Access resource
      // 
      // Multiple threads do enter here!

        Log.v(at_data.TAG, "I_AM_OUT=" + I_AM_IN);
        I_AM_IN = false;
    }
}

我可能错过了一些东西,但没有找到任何说明它不应该工作的文档!?。

输出:

I_AM_IN=false
I_AM_IN=true
I_AM_OUT=true
I_AM_OUT=false

但大多数时候是这样的:

I_AM_IN=false
I_AM_OUT=true
I_AM_IN=false
I_AM_OUT=true

【问题讨论】:

  • 你确定多个线程同时在同步块内吗?
  • 哦,是的。编辑同步块并添加输出。这快把我逼疯了!
  • 我只能认为lock正在改变。也许如果你将它设置为final,你会发现在哪里。
  • 你能发一个完整的例子吗?
  • 另外,Integer.valueOf(0) 不应用作锁。它(可能)是一个共享对象,如果其他类像您一样这样做,您将同步不相关的块,从而导致缓慢(在好的情况下)或死锁(在坏的情况下)。只需改用new Object()

标签: java android constructor synchronized


【解决方案1】:

根据您的评论,问题在于您正在修改锁。您不能增加 Integer 对象的值。整数是不可变的,所以每次你“增加”它时,你都会用另一个锁替换锁:

lock = new Integer(lock.intValue() + 1);

使用 final new Object() 作为锁,并使用单独的变量来保存计数。或者使用 AtomicInteger。 Semaphore 可能也是您正在寻找的类。

经验法则:锁应该始终是最终的。而且你永远不应该使用共享对象作为锁(Integer.valueOf(0) 是共享对象,因为valueOf(0),至少在某些 VM 实现中,总是返回相同的 Integer 实例)。

【讨论】:

  • 感谢最后的提示,出于这个原因,LINT 建议使用 Integer.valueOf,我进行了全局替换;)
  • 顺便说一句,作为一名 C# 开发人员,我成功地将 Integer 用作锁,因为该语言/框架提供了一种增量锁类型的方法(据我所知)。 C# 还允许覆盖 ++ 运算符,这(未经验证)应该使 Integer 类实际上是可变的,因为引用/指针保持不变,但内部数据被修改。这就是我对这一行的期望:lock++;
【解决方案2】:

【讨论】:

  • 为什么会有帮助?我目前使用该锁作为计数器来知道何时不再存在此类的对象,因此不能真正使用 final。无论如何都会尝试看看是否有帮助,使用备用对象进行计数。
  • Nizet 给出了更完整的答案。此外,显式锁定自己非常棘手,并且如您所见,很容易出错。你应该看看执行者。 developer.android.com/reference/java/util/concurrent/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-18
相关资源
最近更新 更多