代码:public class TT  implements Runnable {
   int b=100;
   
    public  void m1 () throws InterruptedException {
b=1500;
Thread.sleep(5000);
System.out.println("b3="+b);
}

     public void m2() throws InterruptedException {
b=2500;
Thread.sleep(2500);
System.out.println("b2="+b);
}
  @Override
public void run() {
// TODO Auto-generated method stub

try {
m1();
} catch (Exception e) {
// TODO: handle exception
  e.printStackTrace();
}

}
    

public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
        TT tt = new TT();
Thread t = new Thread(tt);
t.start();
tt.m2();
System.out.println("b1="+tt.b);
}
}
输出结果: b2=1500,b1=1500,b3=1500  问题1:谁能具体解析下具体代码的执行过程,为什么m2()要先m1()执行?问题2:同时在m1(),m2()前加锁,加关键字 synchronized  输出结果b2=2500,b1=2500,b3=1500 ?? 问题3:分别给m1(),m2() 单独加锁,结果b2,b1,b3都是1500 ??  
谢谢,希望大牛能给点解析,具体怎么执行。

解决方案 »

  1.   


    第一问题:        m2()是否先与m1()开始执行是无法确定的!这个问题不深究
         但是从你的输出可以看出事m2中的b=2500是先于m1中的b=1500执行的
        之后b=1500了,但是由于sleep(5000),程序执行到tt.m2(),而m2只是sleep(2500)因此m2方法先执行首先输出b2=1500
    之后程序顺序执行到System.out.println("b1=" + tt.b);输出b1=1500
    最后执行m1()输出b3=1500
         tips:它们的输出顺序和你睡眠时间有关,但是b的值是一样的!
        无非都是1500或则2500,
    第二个问题:由于你是锁的方法而非对象,且m1、m2都加了锁形成了同步方法
       线程在执行同步方法时是具有排它性的。当任意一个线程进入到一个对象的任意一个同步方法时,这个对象的所有同步方法都被锁定了,在此期间,其他任何线程都不能访问这个对象的任意一个同步方法,直到这个线程执行完它所调用的同步方法并从中退出。
        这里m2方法抢先执行此时m1被锁住b=2500;
    首先输出b2=2500;之后执行到System.out.println("b1="+tt.b);同样输出b1=2500
    最后执行m1,b3=1500,输出b3=1500
    第三个问题:
         单独加锁:在一个对象被某个线程锁定之后,其他线程是可以访问这个对象的所有非同步方法的。
    也就是说,单独加锁的情况和第一种情况是一样的!
      

  2.   

    个人浅见:
    1 关于m2()先于m1()执行,是因为t线程启动后,要等待虚拟机的调度,而m2()就在主线程里运行,(已经在运行了)所以通常是m2()先于m1()运行。m2先执行,会给b赋值2500,但马上休眠了,这会m1会执行,就给b复制1500了,最后输出的都是这个值。2 关于问题2,m1(),m2()都加上synchroniezd关键字,根据上面1 的分析,m2()先执行,因为加了同步,所以在m2()执行时,t线程是在等待状态,m1()不会执行。m2()执行完后,会输出b2=2500. 但接下来输出可能是b1=2500,也可能是b1=1500. 这块是随机的!  因为m2()执行完后,同步锁释放,m1()会运行,但同时主线程也会继续执行,具体哪个先执行,就无法确定了。如果m1()先执行,会输出b1=1500; 反之会输出b1=2500. 最后b3=1500.3 问题3,分别加锁就和没加一样,所以输出和1 一样。
      

  3.   

    "第三问 是没明白方法加锁和对象加锁的不同。。"
    个人理解,不妥望指正:
    给方法加锁,(就是加上synchronized修饰),就是用当前对象(this)作为同步的对象。他的意义是,在我这个方法运行时,其他线程在运行到了使用这个同步对象作为synchronized修饰的方法或代码块时,要等待;或者在别的线程正在运行使用这个同步对象作为synchronized修饰的方法或代码块时,我这个方法也要等待。
    ”对象加锁“,是指对象是被用于做同步用。
    如果只给一个方法加上了“锁”,不存在同步对象争用问题,所以没有意义。对楼主的代码,与不加是一样的。
      

  4.   


    其实方法加锁的方法都是差不多的!
    只是说给对象进行加锁的时候,有时候比直接给方法加锁性能更高而已
    其实说白了给对象加锁,就是控制临界资源的访问权限

        package com.kiritor;  
        /** 
         * @author Kiritor 
         * 饿汉式单例模式*/  
        public class Singleton {  
           private static Singleton singleton = null;  
           private static Object object = new Object();  
           //私有构造方法  
           private Singleton()  
           {  
                 
           }  
           public static Singleton getInstance()  
           {  
              <span style="color:#FF0000;"> if(singleton== null)  
               {  
               synchronized(object)  
               {  
                   /*这里在做一次的判断是: 
                    * 当两个线程同时运行到singleton=null时 
                    * 只能有一个A线程运行,另一个B不能运行 
                    * 但是当不做这层判断的时候,A执行完成后(有了一个实例a), 
                    * B开始执行,由于没有singeton==null的判断B结束之后有了一个实例b 
                    * 这样就不能保证单例了*/  
                   if(singleton== null)  
                      {  
                          singleton = new Singleton();  
                      }  
               }  
                
               }</span>  
               return singleton;  
                     
           }  
        }