这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战
1. synchronized
同步方法与同步块的区别:
1.同步方法
同步方法锁定的是this对象,不是方法。
即有synchronized关键字修饰的方法。由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。代码如:
public synchronized void save(){}
2.同步代码块
即有synchronized关键字修饰的语句块。 被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。代码如:
synchronized(object){
}
注:同步是一种高开销的操作,因此应该尽量减少同步的内容。通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。
在选择加锁对象的时候,加锁的时候应该加在大对象上,防止调用对象不是同一个。
2.volatile
只保证数据同步,当数据修改时立即通知其他持有者更新数据。比synchronized开销小,但不保证操作的原子性。已经很少使用了。
3.使用double-checking和volatile进行单例设计
单例模式:套路,在多线程环境下,对外存在一个对象。 在懒汉式基础上修改。
- 构造器私有化,防止外部创建
- 提供私有的静态属性
- 提供公共的静态方法 静态方法示例:
public static DoubleCheckedLocking getInstance(){
//再次检测,减少不必要的同步。
if(null !== instance){return instance}
synchronized(DoubleCheckedLocking.class){
if(null == instance){
instance = new DoubleCheckedLocking();
}
}
return instance;
}instance
4.可重入锁
原理:锁添加计数器,当加锁对象被访问时,判断是否锁定且为当前持有锁对象,否则wait();,是则计数器加1,当计数器为0时说明对象释放锁。
例子:ReentrantLock。
5.乐观锁和悲观锁
悲观锁
独占锁,会导致其他线程挂起。
乐观锁
没有锁,在提交的时候比较值,如果失败重试,直到成功。
乐观锁实现方式:CAS(Compare and Swap ),中文翻译成比较并交换。
具体实现为需要读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B)。如果内存位置V的值与预期原值A相匹配,那么处理器会自动将该位置值更新为新值B。否则处理器不做任何操作。CAS有效地说明了“我认为位置V应该包含值A;如果包含该值,则将B放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。