java线程锁方法和锁对象_Java 多线程之哪个对象才是锁?

问题背景

在感觉正常的使用ArrayList的迭代删除的操作的时候,发现了如下的崩溃日志:Caused by: java.util.ConcurrentModificationException

at java.util.ArrayList$Itr.remove(ArrayList.java:846)

产生上述崩溃的代码如下:Iterator iterator = strs.iterator();while (iterator.hasNext()) {

String ss = iterator.next();

....

iterator.remove();

}

感觉上述代码是没问题的啊,单线程下我们这么写是没问题的,但是特殊的是此段代码位于一个静态方法里面。没有加同步语句,而且上面还有一个执行添加操作的静态方法,两个方法操作一个静态变量。

看到这里,大概也分析出来了,就是多线程操作同一个变量导致的问题。这时在两个静态方法上面添加synchronized,让它们成为静态同步方法后,问题就解决了。

这时如果我们会多想一下,我们使用了锁解决了同步的问题,但是静态同步方法和实例同步方法在锁这块的机制有什么不同呢?

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

一、静态同步方法问题

如下代码是两个静态同步方法Class A{    public static synchronized void write(boolean b){

isTrue = b;

}    public static synchronized boolean read(){      return isTrue;

}

}

那么我们来问几个问题

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

二、实例同步方法问题

如下代码是两个实例同步方法public synchronized void write(boolean b){

isTrue = b;

}public synchronized boolean read(){  return isTrue;

}

同样问两个问题:

A a=new A(); 线程1访问a.write(false)方法,线程2能访问a.read()方法吗?A a=new A(); A b=new A();线程1访问a.write(false)方法,线程2能访问b.read()方法吗?回答问题之前,先想一下当前方法使用的锁是哪一个?当前线程是否有拿到这把锁?拿到锁了就能访问当前方法了。

三、答案

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

对于实例同步方法,锁是当前实例对象。对于静态同步方法,锁是当前对象的Class对象。对于同步方法块,锁是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对象。

四、理解

谈下自己的一些理解,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的锁,理由同上,不会因为他们有包含关系,导致他们的锁产生嵌套;

控制锁的粒度对编程很重要,这不算技术问题,算是设计,什么是锁的力度呢?

一个人吃饭,占一个座位、还是占一张桌子、还是占一个食堂,是属于范围区域;一个人占着这么大一片区域吃饭后,不走,还要休息,睡觉、干别的,这段时间不让别人进食堂,就是时间区域;两个合并在一起就是粒度;

欢迎来到技术之家,

如需转载,烦请保留本文链接和出处:http://www.jszja.com/contents/14/503.html

您的支持将是我们前进的动力!如对本篇文章有疑问或建议,请通过本站下方邮箱联系我们,让技术之家每天进步一点点!(●'◡'●)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值