写了一段代码,预期变量serialNum增加到10000就停止,可是每次结束的时候,serialNum的结果都是10000多好几百,不知为何,望大家指教。public class Test implements Runnable {
    /**
     * 序列号
     */
    private static int serialNum = 0;
    /**
     * 测试
     */
    public void run() {
        this.increase();
    }
    private synchronized void increase() {
        while (Test.serialNum < 10000) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Test.serialNum++;
            System.out.println("现在的值为:" + Test.serialNum);
        }
    }
    /**
     * @param args
     */
    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            new Thread(new Test()).start();
        }
    }
}控制台输出结果:
…… ……
现在的值为:10992
现在的值为:10993
现在的值为:10994
现在的值为:10995
现在的值为:10996
现在的值为:10997
现在的值为:10998

解决方案 »

  1.   

    public static void main(String[] args) {
            for (int i = 0; i < 1000; i++) {
                Thread t=new Thread(new Test());
                t.start();
                try {
    t.join();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
            }
      

  2.   

    1楼的方法失去了多线程的意义,这个for循环是顺序执行的,要等上一个线程死掉下一个线程再执行。
    你这样的原因在于循环内,每一次都是new出一个对象,synchronized 的锁每new一次就是一个。你这样的写法等于没有同步, 需要一个系统及的单例来当这把锁,比如:
    sychronized (SystemLock) {
      Test.serialNum++;
      System.out.println("现在的值为:" + Test.serialNum);
    }SystemLock 是一个系统级的单例, 虽然加法时也是顺序执行,但作用范围较一楼来的小
      

  3.   

    因为变量serialNum是记录最新的序号,所以我使用了同步方法。关键点在于我希望serialNum增加到10000就停止,可是程序的执行并未如我所愿。
      

  4.   

    你的同步有问题,只对Test同步,但你创建了无数个Test对象,这样就达不到同步的目的了,建议如下改
    private static Object lock;public increase(){
       sychronized(lock){
         .....
       }
    }建议参看:http://blog.csdn.net/Iangao/archive/2008/10/09/3041265.aspx
      

  5.   

    我又看了一下, 你这个例子,可以不用同步的. 下面是我测试通过的. 原子操作不用同步,原代码中的问题是把比较和自增这个过程分开了.
    private void increase() {
            int myNumber;
            while ((myNumber=serialNum++) < 10000) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("现在的值为:" + myNumber);
            }
        }如果一定要分开的话,就必须把整个while放到lock中同步了,否则比较时的serial和自增时的serial一定是不同的.
      

  6.   


    public class Test implements Runnable {
        /**
         * 序列号
         */
        private static Integer serialNum = 0;
        /**
         * 测试
         */
        public void run() {
            this.increase();
        }
        private void increase() {
            synchronized(Test.serialNum) {
                while (Test.serialNum < 10000) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Test.serialNum++;
                    System.out.println("现在的值为:" + Test.serialNum);
                }
            }
        }
        /**
         * @param args
         */
        public static void main(String[] args) {
            for (int i = 0; i < 1000; i++) {
                new Thread(new Test()).start();
            }
        }
    }控制台输出:
    …… ……
    现在的值为:10000
    现在的值为:10000
    现在的值为:10001
    现在的值为:10002
    现在的值为:10003
    现在的值为:10004
    现在的值为:10005
    现在的值为:10006
    现在的值为:10007我的代码是在eclipse里边调试的,刚刚发现一个奇怪的问题:Run的速度很慢,Debug的速度很快,不知道为什么。
      

  7.   

    1. 对于静态变量的同步操作,必须是在静态同步方法里执行才有效,否则同步失效。而在非静态方法中要对静态变量执行操作,只有调用静态同步方法或静态变量自身的同步方法才可以达到同步的目的。
    2. 上述问题可以按照下面两种方法解决
      A. 再把increase()声明成静态同步方法,同时去掉synchronized(Test.serialNum)这时就没用了
      B. 如果increase不能改成静态的.建议还是使用信号量吧,如下:
      private static Semaphore s=new Semaphore(1)
      private void increase(){
         s.p();
         while(..){
           ...
         }
         s.v();
      }
      上述两种均已测试通过,请验证
    3. 正如2楼所说的, 其实这个例子中的同步只起到阻塞做用,并没有同步的执行.因为在执行完10000条循环前同步锁并没有释放.只在一个线程中进行着. 如果是实际应用,建议再细化同步临界区,否则是很难实现同步的.
      

  8.   

    这几天, 我又看了一下这个问题,在7楼时的说法应该是有问题的,本例问题应该出在对Integer对象的同步上,而不是出在static上,如果把同步对象换成一个非基本型(比如Object),同步就会成立了.