同步死锁(String intern())

我用户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工具跟踪informatnio,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在监视器中等待…

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

我曾经向您发布了一个相关问题,您可能需要查看一下: 在String对象上同步问题?

我学到的是:使用intern’ed Strings进行同步是一种不好的做法。

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

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

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

重新思考需要同步的东西。

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

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

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

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

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

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

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

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

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

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

你很可能陷入僵局。

如果要避免死锁,每个线程必须始终以相同的顺序获取锁。 当您使用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."); 

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

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

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

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

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

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

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