在实习字符串上同步

时间:2009-08-31 07:39:24

标签: java concurrency locking

用例示例

  • 我有一个正在接收登录请求的servlet。
  • 如果当前正在登录或者用户已经登录,则servlet应该中止并通知呼叫者。

当前设计

从数据库分片中获取灵感,我计划将每个用户标识的第一个字符用作同步密钥。

void login( String userid )
{
  String first = userid.substring(0, 1);
  synchronized( first.intern() )
  {
    // query the cache or database for a session token.
    // if session token exists, throw an exception
  }
}

问题

  1. 我知道使用 String #intern 可能会溢出permgen空间。在我的例子中,转储到permgen的字符串是一个Unicode字符。我是否可以安全地使用实习字符串?

2 个答案:

答案 0 :(得分:1)

对于你的问题:Perm gen应该能够使用65,536个字符String进行编码(应该只有几个megs)。

然而:

  • 这显然无法在多进程系统上运行。
  • 你冒着死锁的风险(如果其他一些代码在这样的String上进行同步)。
  • 真的很难看。
  • 你真的想要一个适当的节流(!),这应该不会很困难。

答案 1 :(得分:1)

PermGen溢出不是问题。但是:

  1. String.intern()是一个重量级操作,因为它需要锁定String常量池。这会降低您的吞吐量;
  2. 更重要的是,您将同步“逃避”控件的对象,例如如果您使用的库有

    synchronized ("a") {
       // do stuff
    }
    
  3. 阻止某个地方,你会在不知情的情况下陷入僵局。这与在BooleanInteger值上同步的问题大致相同。我建议你使用自己的锁。