『初学请教』Java线程同步问题

请教大虾线程问题,如下代码:
package com.test;

public class Timer {

private static int num = 0;

public synchronized void add(String name) {
    num++;
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println(name + "是第" + num + "个访问的用户");
}

}

package com.test;

public class TestSync implements Runnable {

private Timer t = new Timer();

public void run() {
    t.add(Thread.currentThread().getName());
}

}

package com.test;

public class test {

/**
 * @param args
 */
public static void main(String[] args) {
    Thread t1=new Thread(new TestSync());
    Thread t2=new Thread(new TestSync());
    t1.setName("t1");
    t2.setName("t2");
    t1.start();
    t2.start();
}

}

输出的结果一直是:
t1是第2个访问的用户
t2是第2个访问的用户


疑问: 明明已经给 Timer类的add方法加了synchronized, 为么结果都是显示是第2个访问的用户

请求大神指点,小弟在此谢过!

流程分析:首先主线程执行并开启两个线程t1、t2,接下来就是三个线程争抢CPU控制权,假设t1获得控制权,t1线程新建一个timer对象并调用其add方法(这时add方法用的是此timer对象锁,还有忘记说了mun+1),然后t1线程睡眠一秒,其他线程获得控制权,假设t2线程获得控制权,t2线程又创建一个timer对象并调用add方法(此时add方法的锁改为t2timer的锁,mun又加一次1,此时mun为2),接下来自己分析。手打不易不喜勿喷。

这结果没错啊,只可意会不可言传,有两把锁,线程默认使用的是对象锁(你这里有两个timer对象了),将锁改成累级别的锁,即可得到你想要的结果。手打不易不喜勿喷。

public class Timer {

private static int num = 0;

public void add(String name) {
    synchronized (Timer.class) {   // 类级别锁
        num++;
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(name + "是第" + num + "个访问的用户");
    }
}

}

用同一个对象加锁就好了,一般情况少用类锁

        TestSync test = new TestSync();
        Thread t1=new Thread(test);
    Thread t2=new Thread(test);
    t1.setName("t1");
    t2.setName("t2");
    t1.start();
    t2.start();