This is because the thread that will be executed by the second sets the data value before the first thread prints anything. Doing a slight modification to your code illustrates this pretty well:
public final class ThinkThreadLocal { public static int data; public static void main(String[] args) { for (int i = 0; i < 2; i++) { new Thread(new Runnable() { @Override public void run() { int temp = data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " temp: " + temp); System.out.println(Thread.currentThread().getName() + " shared: " + data); } }).start(); } } }
One execution of this gave me:
Thread-0 temp: 709919531 Thread-1 temp: 2022218312 Thread-0 shared: 2022218312 Thread-1 shared: 2022218312
As you can see, the generated values ββare different (709919531 and 2022218312 in this case), but data overwritten by the second value before the first value is printed. This shows that it is not related to the Random seed.
The second way to show this is to synchronize with the class itself, which (in this case) blocks the thread that is executed by the second, until the first completes execution:
public final class ThinkThreadLocal { public static int data; public static void main(String[] args) { for (int i = 0; i < 2; i++) { new Thread(new Runnable() { @Override public void run() { synchronized (ThinkThreadLocal.class) { data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " shared: " + data); } } }).start(); } } }
as a result
Thread-0 shared: 1811879710 Thread-1 shared: 1738616729
source share