线程安全,synchronized的使用与理解

synchronized从锁的对象的维度来看分为俩种情况

锁住类

由于静态成员不专属于任何一个实例对象,是类成员,因此通过class对象锁可以控制静态 成员的并发操作。需要注意的是如果一个线程A调用一个实例对象的非static synchronized方法,而线程B需要调用这个实例对象所属类的静态 synchronized方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的class对象,而访问非静态 synchronized 方法占用的锁是当前实例对象锁。

另外,从内存的角度来讲,静态成员所分配的内存空间也并不和任何一个对象的内存空间重叠,而是单独在一块内存里面分配。

锁对象实例

由于一个对象只有一个锁,所以只会同步该对象的方法或以此为锁的代码块,如果是相同的类对象,但是是不同的对象实例,他们的方法都是不会同步的。

synchronized修饰的分类

synchronized从修饰方式上可以分为修饰函数和修饰代码块俩种

修饰函数

修饰正常的实例函数:
public synchronized void method(){
	//TODO 此时锁住的是该类的实例对象
}

这种使用方式会使一个实例对象的此方法在不同线程保持同步,但是new出来的不同实例对象调用同一个方法不会保持线程同步
实例方法并不是类所独有的,每个对象实例独立拥有它,它并不被对象实例所共享。这也比较能推出,在实例方法上加入synchronized,那么它获取的就是这个类的锁,锁住的就是这个对象实例。

修饰静态函数:
public static synchronized void method(){
	//TODO 此时锁住的是类对象
}

这种使用方式,不同的实例对象调用或者直接点出调用,都会保持方法同步。
静态方法是属于“类”,不属于某个实例,是所有对象实例所共享的方法。也就是说如果在静态方法上加入synchronized,那么它获取的就是这个类的锁,锁住的就是这个类。

修饰代码块

实例对象
synchronized(this){
	//TODO 此时锁住的是该类的实例对象
}

这种使用方式与上面的修饰实例函数的作用是完全一致的,即相同实例调用保持同步反则亦然

class对象
synchronized(demo.class){
	//TODO 此时锁住的是类对象
}

理解同锁静态方法

任意实例对象Object
//锁住的是配置的实例对象,例如以String对象为锁
String lock = "";
synchronized(lock){
	//TODO 此时锁住的是该类的实例对象Object
}

理解同锁实例对象

原理

synchronized底层原理是使用了对象持有的监视器(monitor)。但是同步代码块和同步方法的原理存在一点差异:

同步代码块是使用monitorenter和monitorexit指令实现的
同步方法是由方法调用指令读取运行时常量池中方法的ACC_SYNCHRONIZED 标识隐式实现,实际上还是调用了monitorenter和monitorexit指令

总结

  1. 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。

  2. 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。

  3. 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值