我用户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()方法可能会死锁,好吗?
答案 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()是一种本机方法 - 可能是问题的原因。