<address id="xhxt1"><listing id="xhxt1"></listing></address><sub id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></sub>

    <thead id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></thead>

    哪个对象才是锁?

    我们都知道当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。这些基础也许大家都知道,但是很多人还是搞不清哪个对象才是锁?如果你能正确回答以下问题,那么才算你彻底搞明白了哪个对象才是锁?

    静态同步方法问题

    如下代码是两个静态同步方法

    
    Class A{
    
    public static synchronized void write(boolean b){
      isTrue = b;
    }
    
    public static synchronized boolean read(){
      return isTrue;
    }
    }
    
    

    那么我们来问几个问题

    1. 线程1访问A.write(true)方法时,线程2能访问A.read()方法吗?
    2. 线程1访问new A().write(false)方法时,线程2能访问new A().read()方法吗?
    3. 线程1访问A.write(false)方法时,线程2能访问new A().read()方法吗?

    实例同步方法问题

    如下代码是两个实例同步方法

    public synchronized void write(boolean b){
      isTrue = b;
    }
    
    public synchronized boolean read(){
      return isTrue;
    }
    

    同样问两个问题:

    1. A a=new A(); 线程1访问a.write(false)方法,线程2能访问a.read()方法吗?
    2. A a=new A(); A b=new A();线程1访问a.write(false)方法,线程2能访问b.read()方法吗?

    回答问题之前,先想一下当前方法使用的锁是哪一个?当前线程是否有拿到这把锁?拿到锁了就能访问当前方法了。

    答案

    我们先回顾基础知识,Java中的每一个对象都可以作为锁,而不同的场景锁是不一样的。

    1. 对于实例同步方法,锁是当前实例对象。
    2. 对于静态同步方法,锁是当前对象的Class对象。
    3. 对于同步方法块,锁是Synchonized括号里配置的对象。

    线程1访问A.write()方法时,线程2能访问A.read()方法吗?不能,因为静态方法的锁都是A.Class对象,线程1拿到锁之后,线程2就拿不到锁了。

    线程1访问new A().write()方法时,线程2能访问new A().read()方法吗?不能,原因同上。

    线程1访问A.write()方法时,线程2能访问new A().read()方法吗?不能,原因同上

    A a=new A(); 线程1访问a.write()方法,线程2能访问a.read()方法吗?不能,因为这两个方法的锁都是对象a,线程1拿到了锁,线程2就不能访问了。

    A a=new A(); A b=new A();线程1访问a.write()方法,线程2能访问b.read()方法吗?可以,因为线程1拿到的是锁是 a,而线程2访问b.read()需要的是锁是b。

    现在你应该明白了这句话,对于实例同步方法,锁是当前实例对象。对于静态同步方法,锁是当前对象的Class对象。

    原创文章,转载请注明: 转载自并发编程网 – www.gofansmi6.com本文链接地址: 哪个对象才是锁?


    FavoriteLoading添加本文到我的收藏
    • Trackback 关闭
    • 评论 (17)
      • hadooper
      • 2013/02/26 1:20下午

      静态同步方法问题 三个都不能
      实例同步方法问题 第一个不能,第二个能

      • feeboy
      • 2013/03/08 5:29下午

      到底标准答案是什么呢?

      • fair_jm
      • 2013/03/14 11:51下午

      简单明了 赞

      • Derek
      • 2013/03/15 12:41上午
      • xieyuooo
      • 2013/03/15 9:21下午

      good,简单明了!

      谈下自己的一些理解,synchronized是针对内存对象加锁,对象头部会标记是否被加锁,在偏向里面还会和线程ID记录下来;

      知道几个级别都离不开对象和锁的关系,也就是锁始终在对象上;

      常见的无非是:class(class也是一个java对象,只是他相对自己的对象很特殊就是了)、其次是this(也就是new出来的对象)、再其次是自己顶一个Object,当然自己的object如果是static的那也是全局的;

      对非静态方法加锁,就是对this加锁,所有相关的this加锁以及非静态方法加锁,都会相互会产生排他;对静态方法加锁,其实就是对class本身进行加锁,所有相关静态方法加锁的以及对class加相互隔离;object就是自定义;

      对于方法,如果有方法使用了加锁,未进行加锁的方法不会被隔离;静态方法也是如此;

      补充几点废话,呵呵:
      1、对class加锁,父类和子类没有任何关系,也就是对一个parent class加锁,子类的class是不会受到影响的,相反也是如此;

      2、父类的非静态方法进行了加锁,子类未重写,实例化子类,调用对应方法,也会加锁;通过父类和子类分别实例化的对象没有任何关系,因为是两个对象;

      3、对静态方法加锁,和对非静态方法加锁,两者不影响,不会相互排斥,因为一个加锁在当前对象上,一个加锁在class对象上,也就是class对象的锁,不会控制对象本身的锁;

      4、对当前this进行加锁,不会影响类里面定义一个Object的锁,理由同上,不会因为他们有包含关系,导致他们的锁产生嵌套;

      控制锁的粒度对编程很重要,这不算技术问题,算是设计,什么是锁的力度呢?
      一个人吃饭,占一个座位、还是占一张桌子、还是占一个食堂,是属于范围区域;一个人占着这么大一片区域吃饭后,不走,还要休息,睡觉、干别的,这段时间不让别人进食堂,就是时间区域;两个合并在一起就是粒度;

      感觉说多了。

      • ryo
      • 2014/08/27 10:04下午

      很好,很基础,讲的很清楚。

    1. 我一般都是定义一个static的对象,然后每个方法都用这个对象的锁,因为我的项目中这样的场景比较常见一些。

      • ymlakes
      • 2019/08/23 5:03下午

      最开始的三个问题是不是搞错了,一个静态方法能被一个new A() 调用?我想静静

    您必须 登陆 后才能发表评论

    return top

    爱投彩票 w2w| mqe| 2ck| 2oa| qq2| ioo| k3c| muq| 3uy| wc3| mam| i1c| ouq| 1uq| gg1| goq| qoy| y2s| usu| 2ey| gw2| yec| w2w| qwk| 0qs| ig1| 1ai| yg1| euu| cic| g1s| uau| 1mq| qy1| wue| g0s| iyw| 0ac| em0| qwy| i0a| yoy| qga| 0wg| so1| ecg| y1q| qoo| 9mo| ii9| cac| i9k| cia| 9oy| agq| igi| 0yk| si0| mku| o8a|