进程并发已经写好了synchronized代码块仍然出现负值?

请前辈们帮忙看下这两段代码:
一:
public class Demo extends Thread {
int num = 10;// 票池
String name;

public Demo(String a) {
    name = a;
}

public static void main(String[] args) {
    Demo d1 = new Demo("售票机1");
    Demo d2 = new Demo("售票机2");
    Demo d3 = new Demo("售票机3");
    Demo d4 = new Demo("售票机4");
    d1.start();
    d2.start();
    d3.start();
    d4.start();
}

public void run() {
    while (num > 0) {
        synchronized (this) {
            System.out.println( name+"------"+"票池剩余票数:" + num--);
            try {
                sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
}

}

二:
public class Demo2 implements Runnable {
int num = 10;

public static void main(String[] args) {
    Demo2 d = new Demo2();
    Thread t1 = new Thread(d);
    Thread t2 = new Thread(d);
    Thread t3 = new Thread(d);
    Thread t4 = new Thread(d);
    t1.start();
    t2.start();
    t3.start();
    t4.start();
}

public void run() {
    while (num > 0) {
        synchronized (this) {
            System.out.println("剩余票数:" + num--);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

    }
}

}

我发现前者输出的数据是四个四个成组出现,后者输出的数据是一个一个出现 。
而且前者输出的数据每一组值都相同。第二组会出现负数 这是为什么?
谢过了。

public class Demo extends Thread {
int num = 10;// 票池
String name;

public Demo(String a) {
    name = a;
}

public static void main(String[] args) {
    Demo d1 = new Demo("售票机1");
    Demo d2 = new Demo("售票机2");
    Demo d3 = new Demo("售票机3");
    Demo d4 = new Demo("售票机4");
    d1.start();
    d2.start();
    d3.start();
    d4.start();
}

public void run() {
String aa="aaa";
    while (num > 0) {
        synchronized (aa) {
            System.out.println( name+"------"+"票池剩余票数:" + num--);
            try {
                sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
}
}