同步死锁(String intern())

时间:2008-12-08 09:21:58

标签: java string deadlock synchronized string-interning

我用户sun jdk 1.5 ThreadPoolExecutor(24,24,60,TimeUnit.SECONDS,new LinkedBlockingQueue())。 soemtime我用jdb工具查找线程池中所有线程的状态是“在监视器中等待”,代码是:

    String key = getKey(dt.getPrefix(), id);
    synchronized (key.intern()) {      ----->

“synchronized(key.intern())”中是否存在问题?


我使用jdb工具获取以下信息,24个线程的状态是“在监视器中等待”,这意味着24个线程在“key.intern()”处死锁。

(java.lang.Thread)0x28 pool-3-thread-2在监视器中等待

(java.lang.Thread)0x27 pool-3-thread-3在监视器中等待

(java.lang.Thread)0x1b pool-3-thread-4在监视器中等待

(java.lang.Thread)0x1a pool-3-thread-5在监视器中等待

(java.lang.Thread)0x19 pool-3-thread-6在监视器中等待

(java.lang.Thread)0x18 pool-3-thread-7在监视器中等待

(java.lang.Thread)0x17 pool-3-thread-8在监视器中等待   ...

所以结果是:在多线程环境中,Sting intern()方法可能会死锁,好吗?

11 个答案:

答案 0 :(得分:5)

我曾向您发送一个相关问题,您可能需要查看一下:Problem with synchronizing on String objects?

我学到的是:使用intern'ed Strings进行同步是一种糟糕练习。

答案 1 :(得分:4)

相当。问题是key.intern()并不是那么独特,因为它从池中返回一个字符串。即使在不同的对象上使用,String.intern()也可能返回相同的对象。尝试使用key本身或完全不同的对象。

答案 2 :(得分:2)

代码几乎肯定会尝试同步影响相同密钥的操作。所以它调用intern()来确保相同的键被映射到同一个对象,因此作为同步对象是有效的。

问题是,如果你遇到了瓶颈(这不是死锁),那就是你有太多的操作同时使用相同的密钥进入。

重新考虑需要同步的内容。

答案 3 :(得分:2)

如果需要在String上进行同步,请不要将String实例用作互斥锁(interned或not inter)。但是,字符串可用于创建一个好的互斥对象:synchronizing on an ID

答案 4 :(得分:2)

你有两个问题。 一个是使用String作为锁。第二个是死锁。

如果您使用String作为锁定,您将失去对“who”和“where”将控制该对象的控制权。

您的死锁问题,可能是也可能不是由String锁定引起的。但是,死锁的实际原因是:“您的代码可能导致死锁。”如果它可能发生,它将会发生。

您必须跟踪线程的堆栈以解决死锁问题。

答案 5 :(得分:2)

这里没有足够的代码来说明出了什么问题。它可能是一个已经提到过的瓶颈,但是至少有一个线程应该运行(CPU使用率相当高)才会发生这种情况,或者一个具有锁定的线程在没有释放锁的情况下进入休眠状态。

死锁是另一种可能,但这需要在多个线程上的两个单独锁上进行同步,并且您在此处只显示了一个锁对象。

如果没有更多信息,确实无法确定。

答案 6 :(得分:1)

正如Bombe所说,key.intern()不一定会给你一个非常独特的同步键。

但是,您应该谨慎地更改代码。在更改代码之前,您需要了解代码中的锁定策略。删除intern()调用可能会为您提供看似正常工作的代码,但包含的数据争用会在以后咬你。

答案 7 :(得分:1)

你很可能陷入僵局。

如果要避免死锁,每个线程必须始终以相同的顺序获取锁。当您使用String.intern()获取锁时,您将锁定整个JVM中的任何代码都可以访问的实例,并锁定。很可能,你自己的代码中的其他线程都是死锁,但它不一定是。

我不确定你在答案中的意思是“key.intern()保证唯一性”。 intern()方法通过为每个等效字符串返回相同的对象来降低唯一性。

  String s1 = new String(new char[] { 'c', 'o', 'm', 'm', 'o', 'n' }).intern();
  String s2 = new String("commo" + (s1.charAt(s1.length() - 1)).intern();
  String s3 = "common";
  if ((s1 == s2) && (s1 == s3))
    System.out.println("There's only one object here.");

上面的代码将证明,即使您创建了两个唯一的实例,通过实习它们,您也可以用一个规范的实例替换它们。

任何时候使用在您自己的代码外部可见的对象作为锁定都存在危险。尽量坚持使用私有成员,不允许从自己的堆栈中逃脱的对象等。

答案 8 :(得分:1)

如何使用带锁定值的唯一字符串前缀并在synchronized块中使用String.intern()。例如,如果要锁定字符串“lock1”,请使用如下的UUID前缀:“85e565b3-d440-46e7-93b6-69ee7e9a63ee-lock1”。这种类型的字符串不应该已经在实习池中。即其他代码出现死锁的可能性非常低。

答案 9 :(得分:-1)

key.intern()保证唯一性,因为key.intern()从String常量池中返回一个字符串。

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html#intern()   实习生

public String intern() 返回字符串对象的规范表示。 最初为空的字符串池由String类私有维护。

答案 10 :(得分:-1)

String.intern()是一种本机方法 - 可能是问题的原因。