2009-08-31 67 views
0

使用情况实例同步上的实习字符串

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

当前设计

从数据库拆分取得灵感,我打算使用每个用户ID的第一个字符作为同步密钥。

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. 据我所知,使用字符串#实习生可能溢出PermGen的空间。在我的情况下,被转储到permgen的字符串是一个Unicode字符。我是否安全地使用这样的字符串?

回答

1

对于你的问题:彼尔姆应该能够用一个字符编码65536 String s(应该只有几个兆字节)。

但是:

  • 这显然不打算在多进程系统的工作。
  • 您运行死锁的风险(如果某些其他代码正在同步String s)。
  • 这真的很丑。
  • 真的你想要一个适当的节流(!),这应该不是很难。
+0

它如何在多处理器机器中不起作用?假设只有一个JVM。如果我使用自己的锁,它与使用实体字符串(在多处理器机器中)有什么不同? – 2009-08-31 08:43:32

+1

他没有说这不适用于多处理器机器。它不适用于多进程系统,即运行多个JVM实例的系统(无论是在单台计算机上还是在多台计算机上) - 'synchronized'在JVM之间不起作用。 – Jesper 2009-08-31 12:12:46

+0

谢谢。我认为这是一个错字。 – 2009-08-31 13:37:15

1

PermGen溢出不是问题。但是:

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

    synchronized ("a") { 
        // do stuff 
    } 
    

块地方,你会死锁而不自知。它与BooleanInteger值的同步问题差不多。我建议你为此使用自己的锁。

+0

谢谢。我正在将我的设计迁移到使用自定义锁的过程中。 – 2009-08-31 08:44:05

+0

'intern'在某种意义上是重量级的,但是当你谈论使用数据库连接等等时,它是相当小的。 – 2009-08-31 20:28:35