首先题主请务必纠正一个误解:线程不安全指的是“不保证会得到预期安全的行为”,而不是“保证不会得到预期安全的行为”。这是个逻辑问题而不是Java、多线程问题。
当您观察到一次实验的结果与预期的“安全”行为一致时,并不代表它就是安全的了。“不保证会得到预期安全的行为”也允许有些时候可以运行得到预期的结果,只是“没有保证”而已。
然而没有保证就是头疼的地方了。您听说过因为没有正确同步而在大并发条件下在HashMap.get()里死循环的案例不?这就是“不保证安全”,然后很多时候似乎也运行得到了预期的结果,然后放上生产环境压一压就垮的案例。
@木女孩说得对。这个并发量级太低了。
另外代码在被JIT编译过后更容易观察到各种有趣的结果。所以把题主的例子稍微调整了一下结构来帮助它预热一小下:
public class UnsafeSequence { private int value; public UnsafeSequence(int value) { this.value = value; } public int getValue(){ return value++; } private static class MyRunnable implements Runnable { private final UnsafeSequence seq; MyRunnable(UnsafeSequence seq) { this.seq = seq; } @Override public void run() { try { Thread.sleep(100); for (int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName() + ":" + seq.getValue()); } } catch (InterruptedException ex) { } } } // warm up MyRunnable.run(), make sure MyRunnable.run() is JIT compiled private static void warmUp() { UnsafeSequence unsafeSequence = new UnsafeSequence(0); MyRunnable r = new MyRunnable(unsafeSequence); // warm up MyRunnable.run() for (int i = 0; i < 100; i++) { r.run(); } } public static void main(String[] args) { warmUp(); UnsafeSequence unsafeSequence = new UnsafeSequence(0); MyRunnable r = new MyRunnable(unsafeSequence); for (int i = 0; i < 5000; i++) { new Thread(r).start(); } } }
截取一段输出给题主参考:
Thread-1439:68297 Thread-1439:585663 Thread-1439:585664 Thread-1439:585665 Thread-1439:585666 Thread-1439:585667 Thread-1439:585668 Thread-1438:68295 Thread-1438:585670 Thread-1438:585671