programe卡在主java线程中

时间:2014-04-09 09:18:58

标签: java multithreading

当我运行以下程序时,它不是从主

出来的
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

public class Ui1 implements Runnable {

    private Set<String> set = new HashSet<String>();

    public static void main(String[] args) {

        Ui1 ui1 = new Ui1();

        Thread t = new Thread(ui1);
        Thread t1 = new Thread(ui1);
        Thread t2 = new Thread(ui1);
        Thread t3 = new Thread(ui1);

        t.start();
        t1.start();
        t2.start();
        t3.start();

    }

    final String getUID() {
        String uuid = UUID.randomUUID().toString();
        StringBuilder builder = new StringBuilder();
        builder.append(uuid);
        return builder.toString();

    }

    @Override
    public void run() {

        for (int i = 0; i < 1000; i++) {

            String s = getUID();

            if (!set.add(s)) {
                System.out.println(s);
            }

        }

    }

}

当我将迭代次数从1000减少到100时,主电源正常退出

这是Threaddump

2014-04-09 14:42:16
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.51-b03 mixed mode):

"DestroyJavaVM" prio=5 tid=0x00007f84b703d800 nid=0x1903 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-1" prio=5 tid=0x00007f84b400d000 nid=0x5903 runnable [0x0000000117d0e000]
   java.lang.Thread.State: RUNNABLE
    at java.util.HashMap.put(HashMap.java:498)
    at java.util.HashSet.add(HashSet.java:217)
    at Ui1.run(Ui1.java:40)
    at java.lang.Thread.run(Thread.java:744)

"Service Thread" daemon prio=5 tid=0x00007f84b5843000 nid=0x5303 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" daemon prio=5 tid=0x00007f84b5033000 nid=0x5103 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" daemon prio=5 tid=0x00007f84b400a000 nid=0x4f03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=5 tid=0x00007f84b502d000 nid=0x4d03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=5 tid=0x00007f84b5841000 nid=0x3903 in Object.wait() [0x0000000117455000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000007aaa85568> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
    - locked <0x00000007aaa85568> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:189)

"Reference Handler" daemon prio=5 tid=0x00007f84b583e800 nid=0x3703 in Object.wait() [0x0000000117352000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000007aaa850f0> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:503)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
    - locked <0x00000007aaa850f0> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=5 tid=0x00007f84b583d800 nid=0x3503 runnable 

"GC task thread#0 (ParallelGC)" prio=5 tid=0x00007f84b5013800 nid=0x2503 runnable 

"GC task thread#1 (ParallelGC)" prio=5 tid=0x00007f84b5014800 nid=0x2703 runnable 

"GC task thread#2 (ParallelGC)" prio=5 tid=0x00007f84b4802000 nid=0x2903 runnable 

"GC task thread#3 (ParallelGC)" prio=5 tid=0x00007f84b4802800 nid=0x2b03 runnable 

"GC task thread#4 (ParallelGC)" prio=5 tid=0x00007f84b5015000 nid=0x2d03 runnable 

"GC task thread#5 (ParallelGC)" prio=5 tid=0x00007f84b5015800 nid=0x2f03 runnable 

"GC task thread#6 (ParallelGC)" prio=5 tid=0x00007f84b5016000 nid=0x3103 runnable 

"GC task thread#7 (ParallelGC)" prio=5 tid=0x00007f84b5800000 nid=0x3303 runnable 

"VM Periodic Task Thread" prio=5 tid=0x00007f84b5843800 nid=0x5503 waiting on condition 

JNI global references: 135

Heap
 PSYoungGen      total 76800K, used 13210K [0x00000007aaa80000, 0x00000007b0000000, 0x0000000800000000)
  eden space 66048K, 20% used [0x00000007aaa80000,0x00000007ab766930,0x00000007aeb00000)
  from space 10752K, 0% used [0x00000007af580000,0x00000007af580000,0x00000007b0000000)
  to   space 10752K, 0% used [0x00000007aeb00000,0x00000007aeb00000,0x00000007af580000)
 ParOldGen       total 174592K, used 0K [0x0000000700000000, 0x000000070aa80000, 0x00000007aaa80000)
  object space 174592K, 0% used [0x0000000700000000,0x0000000700000000,0x000000070aa80000)
 PSPermGen       total 21504K, used 2939K [0x00000006fae00000, 0x00000006fc300000, 0x0000000700000000)
  object space 21504K, 13% used [0x00000006fae00000,0x00000006fb0def18,0x00000006fc300000)

2 个答案:

答案 0 :(得分:2)

我能够重现这一点(不是100%的时间)。正如 fge 所说,HashSet不是线程安全的,您不应该从不同的线程访问它。这样做的结果是不可预测的。

无论如何,试图解释这个特定的病理,我怀疑内部哈希表结构被破坏了。看起来由于线程之间的竞争条件,桶中的链表变为循环。在这种情况下,put操作会继续无限期地查找列表中的键,这就是导致程序卡住的原因。

请注意,为了重现该问题,我在所有线程上添加了join()命令,否则主线程终止,然后所有线程也终止。

要解决此问题,您可以使用以下方法之一:

  • ConcurrentHashMap - 对多个线程非常有效。
  • Collections.synchronizedSet(new HashSet()) - 包装你的设置并使所有设置操作互斥。
  • CopyOnWriteArraySet - 如果有许多读取和少量写入,则效率很高
  • 自己同步访问get()和put() - 如果您需要以原子方式执行其他操作,这非常有用。

答案 1 :(得分:1)

问题是Set set = new HashSet();是从多个线程写的。

有几种方法可以克服这种情况:

  • 我认为最好:避免并发写作(使用不同的集合 不同的线程,然后合并结果)
  • 使用ConcurrentHashSet。至少读取性能比Collections.synchronized()(可能是一个选项)
  • 更好
  • 将!set.add(s)提取到另一个方法并使用关键字synchronized。 (您可以同步您的设置变量,但同步 另一种方法可以提供更好的粒度)

正如我所说,在我看来,最好的事情是设计应用程序,尽可能减少线程之间的共享数据。