关于++操作线程安全问题的疑惑

[code="java"]
public class TestSynchronizedThread implements Runnable{

private static Integer si = 0;

    private static AtomicInteger flag = new AtomicInteger();  

@Override
public void run() {
    for(int k=0;k<200000;k++){
        synchronized(si){
            si++;
        }
    }
}

public static void main(String[] args) throws InterruptedException{

TestMultiThread t1 = new TestMultiThread();

TestMultiThread t2 = new TestMultiThread();

ExecutorService exec1 = Executors.newCachedThreadPool();

ExecutorService exec2 = Executors.newCachedThreadPool();

exec1.execute(t1);

exec2.execute(t2);

while(true){

if(flag.intValue()==2){

System.out.println("si>>>>>"+si);

break;

}

Thread.sleep(50);

}

}  

}[/code]
这段代码最后结果si打印出来小于400000,为什么加了synchronized后++操作还会产生中间状态,而我在JVM字节码中并未找到相应的证据佐证。
下面是主要JVM字节码:
[code="java"]
0: iconst_0
1: istore_1
2: iload_1
3: ldc #2; //int 200000
5: if_icmpge 55
8: getstatic #3; //Field si:Ljava/lang/Integer;
11: dup
12: astore_2
13: monitorenter
14: getstatic #3; //Field si:Ljava/lang/Integer;
17: astore_3
18: getstatic #3; //Field si:Ljava/lang/Integer;
21: invokevirtual #4; //Method java/lang/Integer.intValue:()I
24: iconst_1
25: iadd
26: invokestatic #5; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
29: dup
30: putstatic #3; //Field si:Ljava/lang/Integer;
33: astore 4
35: aload_3
36: pop
37: aload_2
38: monitorexit
39: goto 49
42: astore 5
44: aload_2
45: monitorexit
46: aload 5
48: athrow
49: iinc 1, 1
52: goto 2
55: return
[/code]
希望各位大侠能帮小弟指点一下迷津。

si++执行后,都会指向一个新的对象。
synchronized(si),每次进来时si并不是同一个对象。不同对象的上的锁当然不行了。