本人免费整理了Java高级资料,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并发分布式等教程,一共30G,需要自己领取。
传送门:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q

锁的简单应用

用lock来保证原子性(this.count++这段代码称为临界区)

什么是原子性,就是不可分,从头执行到尾,不能被其他线程同时执行。

可通过CAS来实现原子操作

CAS(Compare and Swap):

CAS操作需要输入两个数值,一个旧值(期望操作前的值)和一个新值,在操作期间先比较下旧值有没有发生变化,如果没有发生变化,才交换成新值,发生了变化则不交换。

CAS主要通过compareAndSwapXXX()方法来实现,而这个方法的实现需要涉及底层的unsafe类

unsafe类:java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作

public class Counter{
private Lock lock = new Lock();
private int count = ;
public int inc(){
lock.lock();
this.count++;
lock.unlock();
return count;
}
}

不可重入锁

先来设计一种锁

public class Lock{
private boolean isLocked = false;
public synchronized void lock() throws InterruptedException{
while(isLocked){
wait();
}
isLocked = true;
}
public synchronized void unlock(){
isLocked = false;
notify();
}
}

这其实是个不可重入锁,举个例子

public class Count{
Lock lock = new Lock();
public void print(){
lock.lock();
doAdd();
lock.unlock();
}
public void doAdd(){
lock.lock();
//do something
lock.unlock();
}
}

当调用print()方法时,获得了锁,这时就无法再调用doAdd()方法,这时必须先释放锁才能调用,所以称这种锁为不可重入锁,也叫自旋锁。

可重入锁

设计如下:

public class Lock{
boolean isLocked = false;
Thread lockedBy = null;
int lockedCount = ;
public synchronized void lock()
throws InterruptedException{
Thread thread = Thread.currentThread();
while(isLocked && lockedBy != thread){
wait();
}
isLocked = true;
lockedCount++;
lockedBy = thread;
}
public synchronized void unlock(){
if(Thread.currentThread() == this.lockedBy){
lockedCount--;
if(lockedCount == ){
isLocked = false;
notify();
}
}
}
}

相对来说,可重入就意味着:线程可以进入任何一个它已经拥有的锁所同步着的代码块。

第一个线程执行print()方法,得到了锁,使lockedBy等于当前线程,也就是说,执行的这个方法的线程获得了这个锁,执行add()方法时,同样要先获得锁,因不满足while循环的条件,也就是不等待,继续进行,将此时的lockedCount变量,也就是当前获得锁的数量加一,当释放了所有的锁,才执行notify()。

如果在执行这个方法时,有第二个线程想要执行这个方法,因为lockedBy不等于第二个线程,导致这个线程进入了循环,也就是等待,不断执行wait()方法。只有当第一个线程释放了所有的锁,执行了notify()方法,第二个线程才得以跳出循环,继续执行。

这就是可重入锁的特点。

java中常用的可重入锁

synchronized

java.util.concurrent.locks.ReentrantLock

  • AtomicIntegerFieldUpdater:原子更新整型的字段的更新器
  • AtomicLongFieldUpdater:原子更新长整型字段的更新器
  • AtomicStampedReference:原子更新带有版本号的引用类型。该类将整型数值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解决使用CAS进行原子更新时可能出现的ABA问题。
  • AtomicReference :原子更新引用类型
  • AtomicReferenceFieldUpdater :原子更新引用类型里的字段
  • AtomicMarkableReference:原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和应用类型
  • AtomicIntegerArray :原子更新整型数组里的元素
  • AtomicLongArray :原子更新长整型数组里的元素
  • AtomicReferenceArray : 原子更新引用类型数组的元素
  • AtomicBooleanArray :原子更新布尔类型数组的元素
  • AtomicBoolean :原子更新布尔类型
  • AtomicInteger: 原子更新整型
  • AtomicLong: 原子更新长整型

最新文章

  1. 通过Mono 在 Heroku 上运行 .NET 应用
  2. 使用自定义 classloader 的正确姿势
  3. iOS使用Zbar扫描二维码
  4. Windows Server 2012 克隆修改SID
  5. Get,Post请求中文乱码问题有效解决方法
  6. IIS安装和使用(Windows Server 2003)
  7. FME之于规划CAD数据质量检测
  8. Unity3d删除无用的美术资源
  9. Vertex中实现每顶点光照的镜面高光效果
  10. oracle 将查询到的数据插入表
  11. parseSdkContent failed Could not initialize class android.graphics.Typeface
  12. MFC线程(三):线程同步事件(event)与互斥(mutex)
  13. php number_format()保留小数点后几位有效数的函数 千位分组来格式化数字(转)
  14. TCP与UDP区别总结
  15. 【原创】c++拷贝初始化和直接初始化的底层区别
  16. 失物找寻APP软件需求规格说明书——第三次团队作业
  17. chrome 自动加载flash
  18. python3.4连接mysql5.7数据库增删改查
  19. 第一个驱动之字符设备驱动(二)mdev
  20. poj1088(记忆化搜索入门题)

热门文章

  1. 新闻实时分析系统-HBase分布式集群部署与设计
  2. day 42 JavaScript 基础知识部分
  3. win10 下安装zookeeper+Kafka 的详细步骤(2)
  4. scrapy抓取豆瓣电影相关数据
  5. java 抽象类和接口整理
  6. js如何衔接css3的多个@keyframes动画?
  7. GItBook命令使用(持续更新)
  8. 大型情感剧集Selenium:6_selenium中的免密登陆与cookie操作
  9. 编译原理 算法3.8 LR分析 c++11实现
  10. 开发者应该掌握 WebSocekt 协议的知识