你只是同步了increase方法内部和getValue方法内部,在方面调用之间和与其他方法一块用时,无法保证同步。要想不重复就把打印的代码和增加value的代码放到一个同步代码块里面。

解决方案 »

  1.   

    谢谢 经过楼上提醒 我把代码改成了这样 问题貌似解决了 但是又有一个新问题了,我把Count类中的synchronized去掉,打印的结果居然跟同步的一模一样。这样怎么才能区分出synchronized的同步性呢?
    class ThreadTest implements Runnable {
    Count c = new Count(); @Override
    public void run() {
    c.increase();
    System.out.println(c.getValue());
    }

    public void print() {
    }
    }
      

  2.   

    不知道你的代码想实现一个什么功能。
     new Thread(a).start();
     a.print();
    这两行什么意思啊?完全没有体现多线程与同步的思想啊。
    你在一个线程里面实现count+1,在主线程里面调用print方法,有什么意义呢?如下是我修改了你的代码,同时给你一个,我写的一个例子。希望对你有帮助。
    public class Test22{
      
        public static void main(String[ ] args) {
         ThreadTest a = new ThreadTest();
            for(int i=0;i<100;i++){
                new Thread(a).start();
    //            a.print();
            }
            
            
        }
    }
     
    class ThreadTest implements Runnable {
        Count c = new Count();
     
        public void run() {
            c.increase();
        }
         
    //    public void print() {
    //        System.out.println(c.getValue());
    //    }
    }
     
    final class Count {
        private long value = 0;
         
        public synchronized long getValue() {
            return value;
        }
         
        public synchronized long increase() {
            if(value == Long.MAX_VALUE) {
                throw new IllegalStateException("error");
            }
            System.out.println(++value);
            return value;
        }
    }public class VolatileTest { static Integer count = 0;

    static volatile Integer countVolatile = 0;

    static Integer countSynchronizedMethod = 0;

    static Integer countSynchronizedAttribute = 0;

    static void addCount(){
    try {
    Thread.sleep(1);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    count ++;
    }

    static void addCountVolatile(){
    try {
    Thread.sleep(1);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    countVolatile ++;
    }

    static synchronized void addCountSynchronizedMethod(){
    try {
    Thread.sleep(1);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    countSynchronizedMethod ++;
    }

    static void addCountSynchronizedAttribute(){
    synchronized(countSynchronizedAttribute){
    try {
    Thread.sleep(1);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    countSynchronizedAttribute ++;
    }

    }

    /**
     * 功能:
     * @param args
     */
    public static void main(String[] args) {

    ThreadGroup group = new ThreadGroup("test");

    for (int i = 0; i < 1000; i++) {
    Thread thread = new Thread(group,""){
    public void run() {
    addCount();
    addCountVolatile();
    addCountSynchronizedMethod();
    addCountSynchronizedAttribute();
    }
    };

    thread.start();
    }

    try {
    Thread.sleep(3000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }


    System.out.println("count:" + count);
    System.out.println("countVolatile:" + countVolatile);
    System.out.println("countSynchronized:" + countSynchronizedMethod);
    System.out.println("countSynchronizedAttribute:" + countSynchronizedAttribute);

    }}
     
      

  3.   

     private long value = 0;
    我虽然不太清楚楼主的意图,但我觉得问题出在value字段
    这是一个成员变量,每个对象都有自己独立的堆内存空间,而每个对象的value值都是从0开始,所以肯定会有重复的值
    解决办法:
    设置成静态变量,那么只会在类中维持一份拷贝
    private staticf long value = 0;
      

  4.   

    只因你NEW 了count,不是同一个对象了已经。
      

  5.   

    1楼里面的代码会出现问题是因为你在main方法中调用了a.print方法. 这个时候前面一行语句new Thread(a).start()并不一定就执行了.(换句话说就是这个在main方法中执行到a.print())的时候前面启动的线程中的run()方法并不一定就已经执行.)
    后来的代码中出现加不加synchronized关键字都一样的情况其实只是错觉.因为你电脑够快, 所以每次运行的时候都是直接过掉了. 如果你的代码在run方法里面的increae()方法和System.out.println()中间加上其他代码的话就有可能引起打印数据异常的情况. 所以还是要添加synchronized关键字
    另外, 您这个程序中虽然可以保证每次都打印从1~100, 但是你没法保证打印出来的数字的顺序.
    这一点你可以在run()方法两行代码中加入一个for循环(1~100的循环就够了)就可以看出来.
      

  6.   

    ---------------------关键是要把两个动作increase和print同步在一起。你代码中的同步synchronized 都是没有意义的。你比较一下下面两个不同方案的执行结果吧:// 方案1 :同步
    public void run() {
      synchronized (c) {  // 这里是关键,把(动作1,动作2)同步
                          // 这意味着,在动作1和动作2之间,别的线程插不进来
        c.increase(); // 动作1

        try {
          Thread.currentThread().sleep(100); // Sleep 加强观察效果
        } catch (InterruptedException e) {}
        
        System.out.println(c.getValue()); // 动作2
      }
    }// 方案2:无同步
    public void run() {
        c.increase(); // 动作1

        try {
          Thread.currentThread().sleep(100); // Sleep 加强观察效果
        } catch (InterruptedException e) {}
        
        System.out.println(c.getValue()); // 动作2
    }
    另外,// 方案1 :同步
    public void run() {
      synchronized (c) {
        //...body
      }
    }// 等同于:
    public synchronized void run() {
        //...body
    }
      

  7.   

    推荐两篇文章,对LZ理解有益
    http://ifeve.com/who-is-lock/
    http://ifeve.com/race-conditions-and-critical-sections/
    http://ifeve.com/locks/
      

  8.   

     new Thread(a).start();
      a.print();
    这两句的执行顺序没法保证吧```