A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 史政法 中级黑马   /  2013-3-29 19:36  /  2082 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 史政法 于 2013-3-30 10:22 编辑
  1. class Bank
  2. {
  3.         private int sum;
  4.         //Object obj = new Object();
  5.         public synchronized void add(int n)
  6.         {
  7.                 //synchronized(obj)
  8.                 //{
  9.                         sum = sum + n;
  10.                         try{Thread.sleep(10);}catch(Exception e){}
  11.                         System.out.println("sum="+sum);
  12.                 //}
  13.         }
  14. }

  15. class Cus implements Runnable
  16. {
  17.         private Bank b = new Bank();
  18.         public void run()
  19.         {               
  20.                 for(int x=0; x<3; x++)
  21.                 {
  22.                         b.add(100);
  23.                 }
  24.         }
  25. }


  26. class  BankDemo
  27. {
  28.         public static void main(String[] args)
  29.         {
  30.                 Cus c = new Cus();
  31.                 Thread t1 = new Thread(c);
  32.                 Thread t2 = new Thread(c);
  33.                 t1.start();
  34.                 t2.start();
  35.         }
  36. }
复制代码
讲到同步函数中用的锁是this,可是这个this,t1调用的时候不是代表t1吗,t2线程调用的时候不又是t2了吗???代表的对象不一样的啊?为什么也可以实现同步?而不像是直接new一个Object对象,然后全都用Object的锁,一把锁,一个对象,,这样的同步我能理解,为什么this每次的引用不一样也能同步?原理是什么?

点评

如果仍有问题,请继续追问,如果问题已解决,请将分类改为已解决,谢谢  发表于 2013-3-30 08:00

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

7 个回复

倒序浏览
这里的this代表的是Bank的对象,是多个线程对同一个对象进行操作,所以才会产生线程安全问题。
t1和t2是两个线程对象,他们内部都是对同一个Cus的同一个银行账户操作,操作的数据sum,为了防止多行对sum使用的代码产生不同的结果,使用了同步,而add方法是Bank的一个普通方法,所以锁是this

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
王亚东 发表于 2013-3-29 19:46
这里的this代表的是Bank的对象,是多个线程对同一个对象进行操作,所以才会产生线程安全问题。
t1和t2是两 ...

怎么可能this代表的是Bank,,,Bank什么时候调用过add方法了。。。。。this代表的是对象的引用,而每次引用都不一样,t1引用,t2引用,而每次的引用不一样,为什么还可以实现同步函数?
回复 使用道具 举报
史政法 发表于 2013-3-29 19:57
怎么可能this代表的是Bank,,,Bank什么时候调用过add方法了。。。。。this代表的是对象的引用,而每次 ...

打个比方吧:
你就是一个Cus对象,b对象你的一个银行账户,不论你有多少朋友往你帐号里打钱,这个锁始终是在银行那边,
你就是把帐号发到网上,全国人都往帐号里打钱,锁依旧是在银行你的帐号上。
而这些人就是线程,不可能全国人没人都有一把锁吧。锁只有一把,就是你的帐号的
回复 使用道具 举报
这个是与毕老师讲的卡车运煤的例子相似啊,就是多线程操作同一个对象。是你理解错了,this代表的不是线程对象,而是多线程要操作的对象(也就是Bank对象)。你看看毕老师的代码:
  1. class Res
  2. {
  3.         String name;
  4.         String sex;
  5.         boolean flag = false;
  6. }

  7. class Input implements Runnable
  8. {
  9.         private Res r ;
  10.         Input(Res r)
  11.         {
  12.                 this.r = r;
  13.         }
  14.         public void run()
  15.         {
  16.                 int x = 0;
  17.                 while(true)
  18.                 {
  19.                         synchronized(r)
  20.                         {

  21.                                 if(r.flag)
  22.                                         try{r.wait();}catch(Exception e){}
  23.                                 if(x==0)
  24.                                 {
  25.                                         r.name="mike";
  26.                                         r.sex="man";
  27.                                 }
  28.                                 else
  29.                                 {
  30.                                         r.name="丽丽";
  31.                                         r.sex = "女女女女女";
  32.                                 }
  33.                                 x = (x+1)%2;
  34.                                 r.flag = true;
  35.                                 r.notify();
  36.                         }
  37.                 }
  38.         }
  39. }

  40. class Output implements Runnable
  41. {
  42.         private Res r ;
  43.        
  44.         Output(Res r)
  45.         {
  46.                 this.r = r;
  47.         }
  48.         public void run()
  49.         {
  50.                 while(true)
  51.                 {
  52.                         synchronized(r)
  53.                         {
  54.                                 if(!r.flag)
  55.                                         try{r.wait();}catch(Exception e){}
  56.                                 System.out.println(r.name+"...."+r.sex);
  57.                                 r.flag = false;
  58.                                 r.notify();
  59.                         }
  60.                 }
  61.         }
  62. }


  63. class  InputOutputDemo
  64. {
  65.         public static void main(String[] args)
  66.         {
  67.                 Res r = new Res();

  68.                 Input in = new Input(r);
  69.                 Output out = new Output(r);

  70.                 Thread t1 = new Thread(in);
  71.                 Thread t2 = new Thread(out);

  72.                 t1.start();
  73.                 t2.start();
  74.         }
  75. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 HM朱蛟 于 2013-3-29 23:12 编辑

楼主你好,看了许久,楼主的疑惑点我大致明白了 我说下我的看法吧 有什么不对的请指出 一起学习

首先,这个bank类的对象,他的对象是Cus里创建的,Bank b = new Bank()它才叫做是对象调用; 所以只能是b指向了Bank对象,该对象的方法也是在Cus类里run()里调用了b.add()方法,简单说,它也属于多线程执行代码的一部分。

其实你搞混了一个概念,this是指向当前对象的引用,这没错,但是Thread(c)并非是一个指向它的动作,他只是可以接收一个Runnable的子类对象引用,和Bank b = new Bank() 这样的对象调用是有区别的,

总结:
你的当前调用对象自始至终都只有一个,即 Bank b = new Bank();换句话说,你的this锁自始至终也只有一个。
只需要搞清楚Thread t1 = new Thread(c)只是开启一个线程,c是传递的参数,是为了让线程找到线程执行代码,而该线程代码又是放在run()方法中,run方法只能是实现了Runnable接口的子类来复写或者直接是继承了Thread类的子类来复写提供的。
总之要明白,Thread t1 = new Thread(c) 和Bank b = new Bank()的区别

希望可以帮到你。

另附一个验证同步函数的锁是this的例程,看懂了这个例子相信你对同步函数的锁就没什么疑问了:
思想:
用两个线程,一个线程分别用一种同步方式
线程1:用同步代码块
线程2:用同步函数
利用一个布尔标志位手动分流。
class Ticket implements Runnable
{
  private int tick = 100; //卖100张票

  //Object o = new Object();

  boolean b = true;//标志位分流

  public void run()//卖票的代码要被多个线程所执行,存在于run方法中
  {
    if(b)
      while(true)//一直循环,无特殊意义
      {
              //synchronized(o)
                                                        synchronized(this)
        {
           if(tick>0)//不能卖出0号票
           {
             try {Thread.sleep(10);} catch (Exception e) {}
                   System.out.println(Thread.currentThread().getName()+"卖 :code"+tick--);
                  //注意实现的话不能直接调用currentThread
           }
        }
      }
    else      
      while(true)//一直循环,无特殊意义
      show();//调用同步函数
  }

  synchronized void  show() //同步函数的锁是this
  {
     if(tick>0)//不能卖出0号票
     {
       try {Thread.sleep(10);} catch (Exception e) {}

       System.out.println(Thread.currentThread().getName()+"卖 :show........."+tick--);
      //注意实现的话不能直接调用currentThread
     }
  }
}

class TicketDemo
{
  public static void main(String[] args)
  {
           Ticket t = new Ticket();//售票窗口
       
           Thread t1 = new Thread(t); //传参
           Thread t2 = new Thread(t);
       
                 t1.start(); //开启线程
                 
           try {Thread.sleep(10);} catch (Exception e) {}
           t.b = false;
           t2.start();
  }      
}
输出结果:
Thread-1卖 :show.........2
Thread-0卖 :code1
Thread-1卖 :show.........0  --->错票
思考:
为何同步了还是有错票?思考点应放在2个前提上,前提1:至少双线程。 前提2:同一个锁。从2个前提着手。我们知道,run函数是会被对象调用的,那么他的synchronized锁就是this,那么我们不妨把同步代码块的锁也改成this试一试。因为他们操作的都是同一个数据。
synchronized(o)--->synchronized(this)
改了过后,结果正常了,那么说明,2个前提满足了,所以能断定,同步函数用的是this的锁。

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
明白了,谢谢楼上几位。。。。。。
回复 使用道具 举报
this代表的却是是Bank对象,,,,,是因为run方法中调用的是b
回复 使用道具 举报 1 0
您需要登录后才可以回帖 登录 | 加入黑马