Java 在内部字符串上同步

Java 在内部字符串上同步,java,concurrency,locking,Java,Concurrency,Locking,用例示例 我有一个servlet正在接收登录请求 如果当前正在登录或用户已经登录,servlet应该中止并通知调用方 当前设计 受数据库切分的启发,我计划使用每个用户ID的第一个字符作为同步键 void login( String userid ) { String first = userid.substring(0, 1); synchronized( first.intern() ) { // query the cache or database for a se

用例示例

  • 我有一个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
  }
}
问题

  • 我知道使用String#intern可能会使permgen空间溢出。在我的例子中,转储到permgen中的字符串是单个Unicode字符。我用这种方式使用实习字符串安全吗

  • 对于您的问题:Perm gen应该能够使用65536编码一个字符
    String
    s(应该只有几个兆)

    然而:

    • 这显然不适用于多进程系统
    • 您将面临死锁的风险(如果其他代码正在此类
      字符串上同步)
    • 真难看
    • 你真的想要一个合适的节流(!),这应该一点也不难

      • 永久性溢出不是问题。然而:

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

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

      • 阻塞某个地方,您将在不知情的情况下死锁。这与在
        Boolean
        Integer
        值上同步差不多。我建议您为此使用自己的锁。

        在多处理器机器中,它怎么会不起作用?假设只有一个JVM。如果我使用自己的锁,它与使用内部字符串(在多处理器机器中)有何不同?他没有说这在多处理器机器上不起作用。它在多进程系统上不起作用,也就是说,在一个系统中,有多个JVM实例在运行(在一台计算机上或多台计算机上)-“synchronized”不能跨JVM工作。谢谢。我以为那是个打字错误。谢谢。我正在将我的设计迁移到使用自定义锁的过程中。
        intern
        在某种意义上是重量级的,但是当你谈论使用数据库连接之类的东西时,它相对来说是很小的。请参阅