请问哪位大神能解释一下,synchronized修饰方法和作为块的区别呢?例如以下代码: public class Counter {
 
    public  static Integer count = 0;
 
    public static void inc() {
 
        //这里延迟1毫秒,使得结果明显
        try {
            Thread.sleep(30);
        } catch (InterruptedException e) {
        }
        //注意看这里。监控count了。
        synchronized(count){
        count++;
        System.out.println(count);
        }
    }
 
    public static void main(String[] args) {
 
        //同时启动1000个线程,去进行i++计算,看看实际结果
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                }
            }).start();
        }
 
        //这里每次运行的值都有可能不同,可能为1000
        System.out.println("运行结果:Counter.count=" + Counter.count);
    }
}为什么synchronized作为块的时候得出的结果可能不是1000,而如果改为修饰方法inc时结果却可以正确,为1000呢?

解决方案 »

  1.   

    synchronized修饰块和修饰方法是一样的,修饰块的话粒度可以更小,非静态的synchronized修饰方法的话就是锁这个方法所对应的类的对象,静态的synchronized 修饰方法的话所的是这个方法所对应的类,synchronized 块的话如果里面直接写this的话效果和非静态的synchronized修饰方法是一样的,不过他还可以不锁住对象 还可以粒度小一点 ,比如吧类中的一个变量作为锁
      

  2.   

    @楼上,"synchronized修饰块和修饰方法是一样的",很多书也是这么说。但是为什么例如上面这个模拟高并发情况下,synchronized修饰块和方法时,程序运行的结果会不一样呢?
      

  3.   

    @楼上,“synchronized修饰块和修饰方法是一样的”,很多书也这么说。但是上面例子程序,模拟高并发情况下,为什么用synchronized修饰方法可以获得正确结果,修饰块就不能呢?感觉很奇怪。能解释下吗?
      

  4.   

    public synchronized static void inc()
    应该是你这个方法的原因吧,它是静态方法,线程锁的是Counter 的CLASS对象,而不是Counter 的对象。
    你循环1000次 就是调用Counter 的CLASS对象的inc方法1000次。
      

  5.   

    synchronized锁定的是实例块,但是你的count是static的对象,并且你的方法也是static的方法,所以你用实例锁去锁class对象根本没用的!!!所以你需要把synchronized放到方法上锁定static方法,也就是锁的class对象了。如果你需要用synchronized块的话,需要把方法改成非静态方法
      

  6.   

    还有lz你是不能根据System.out.println("运行结果:Counter.count=" + Counter.count);
    来看最后结果的,这句话不一定是在最后执行的。
      

  7.   

    package com.djk.thread;public class Counter 
    {
      
     //首先你以前来锁这个对象是错的 他是会变的
      public static Integer count =0;
      
      //现在我给你重弄一把锁,这把锁是静态的保证只有一个对象是同一把锁
      private static Object object = new Object();
      
      //这里要改成非静态的  你也可以再这里加synchronized 效果也是1000,主要线程中都是同一个对象调用这个方法
      public  void inc()
      {
      
      //这里延迟1毫秒,使得结果明显
      try
      {
      Thread.sleep(30);
      }
      catch (InterruptedException e) 
      {
      
      }
      //这里不要锁count是没用的,锁object 最后执行的结构是1000
      synchronized(object)
      {
      count++;
      System.out.println(count);
      }
      }
      public static void main(String[] args)
      {
      //同时启动1000个线程,去进行i++计算,看看实际结果
      //这边这样定义是为了保证线程中时同一个对象调用方法
     final Counter c = new Counter();
      for (int i = 0; i < 1000; i++) {
      new Thread(new Runnable() {
      @Override
      public void run()
      {
      c.inc();
      }
      }).start();
      }
      
      //这里每次运行的值都有可能不同,可能为1000
      //还有这里是没必要写的,看这个是看不出结果的,这句话是主线程的,主线程不一定是在最后执行,可能在你生成线程的时候就执行了
      System.out.println("运行结果:Counter.count=" + Counter.count);
      }
    }lz你参考下这是我按照你代码改的加的批准
      

  8.   

    @chengxu2011,的确不一定最后执行,所以我才在上面同步方法上打印出每个值,这样,如果没有并发问题的话,那堆值中一定有1000出现,但是很奇怪,每次运行的最大值都可能不一样。
      

  9.   


    得不到正确结果的原因是:你能保证你执行System.out.println("运行结果:Counter.count=" + Counter.count);这条命令的时候,你那1000个线程都执行结束了吗?
    你可以在启动那1000个线程后让主线程睡上一会,你就可以得到正确结果了
      

  10.   

    @chengxu2011,你说对了,是锁对象的问题,为什么不能锁count呢?虽然它的值会改变,但是改变了“值”,它就不再是以前的对象了吗?
      

  11.   

    呵呵 这个我也刚刚发现的,你这个问题我现在也在研究,为什么锁count没用,我感觉是count++的时候count都不是以前的对象了
      

  12.   

     Integer的源码有这么一句:
       /**
         * The value of the <code>Integer</code>.
         *
         * @serial
         */
        private final int value;
    之前还真不知道原来它的value是不可改变的!!!那Integer效率看来不行啊。
      

  13.   


    synchronized(Counter.class){
      count++;
      System.out.println(count);
    }count是属于Counter 的CLASS的,而不是属于每个Counter对象。