本人免费整理了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: 原子更新长整型

探索JAVA并发 - 可重入锁和不可重入锁的更多相关文章

  1. Java并发编程原理与实战四十二:锁与volatile的内存语义

    锁与volatile的内存语义 1.锁的内存语义 2.volatile内存语义 3.synchronized内存语义 4.Lock与synchronized的区别 5.ReentrantLock源码实 ...

  2. [Java并发] AQS抽象队列同步器源码解析--独占锁释放过程

    [Java并发] AQS抽象队列同步器源码解析--独占锁获取过程 上一篇已经讲解了AQS独占锁的获取过程,接下来就是对AQS独占锁的释放过程进行详细的分析说明,废话不多说,直接进入正文... 锁释放入 ...

  3. 转:【Java并发编程】之七:使用synchronized获取互斥锁的几点说明

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17199201     在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访 ...

  4. Java并发编程(九)-- 进程饥饿和公平锁

    上一章已经提到“如果一个进程被多次回滚,迟迟不能占用必需的系统资源,可能会导致进程饥饿”,本文我们详细的介绍一下“饥饿”和“公平”. Java中导致饥饿的原因 在Java中,下面三个常见的原因会导致线 ...

  5. 【Java并发编程】之七:使用synchronized获取互斥锁的几点说明

    在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访问对象并要求操作相同资源时,分割了原子操作就有可能出现数据的不一致或数据不完整的情况,为避免这种情况的发生,我们会采取同步机制,以确 ...

  6. java并发编程(四)----(JUC)Lock锁初探

    首先我们来回忆一下上一节讲过的synchronized关键字,该关键字用于给代码段或方法加锁,使得某一时刻它修饰的方法或代码段只能被一个线程访问.那么试想,当我们遇到这样的情况:当synchroniz ...

  7. 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock)

    一.前言 优秀的源码就在那里 经过了前面两章的铺垫,终于要切入正题了,本章也是整个AQS的核心之一 从本章开始,我们要精读AQS源码,在欣赏它的同时也要学会质疑它.当然本文不会带着大家逐行过源码(会有 ...

  8. Java并发编程-线程可见性&线程封闭&指令重排序

    一.指令重排序 例子如下: public class Visibility1 { public static boolean ready; public static int number; } pu ...

  9. 探索JAVA并发 - 终于搞懂了sleep/wait/notify/notifyAll

    > sleep/wait/notify/notifyAll分别有什么作用?它们的区别是什么?wait时为什么要放在循环里而不能直接用if? ## 简介 首先对几个相关的方法做个简单解释,Obje ...

随机推荐

  1. 像黑客一样写博客–Pelican快速搭建静态博客

    "像黑客一样写博客",通过文本编辑器(Markdown编辑器)即可实现写博客,而且是静态的,很神奇吧,这里的方案是Pelican. 为啥叫 Pelican 这么奇怪的名字 &quo ...

  2. 教你用Java web实现多条件过滤功能

    生活中,当你闲暇之余浏览资讯的时候,当你搜索资料但繁杂信息夹杂时候,你就会想,如何更为准确的定位需求信息.今天就为你带来: 分页查询 需求分析:在列表页面中,显示指定条数的数据,通过翻页按钮完成首页/ ...

  3. 常见 MIME 类型列表(转)

    本文转自:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MI ...

  4. Glibc编译报错:*** These critical programs are missing or too old: as ld gcc

    Binutils版本升级 这里是binutils版本过低导致, 查看已部署版本 上传离线升级包 [root@sdw1 glibc]# tar -zxvf binutils-2.32.tar.gz [r ...

  5. JS的静态类型检测,有内味儿了

    我们知道 TypeScript 2.3 以后的版本支持使用--checkJs对.js文件进行类型检查和错误提示. 但是由于 JavaScript 是弱类型语言,在编写代码的时候,是无法检测变量的类型的 ...

  6. 转:spring4.0之二:@Configuration的使用

    从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplic ...

  7. composer install 或 update 速度慢的解决方案(composer加速)

    我们在使用composer install和composer update时,有的时候安装和更新速度非常慢,我们可以通过下面的几个方法来解决这个问题. 首先查看一下当前的 composer 全局配置地 ...

  8. JS的对象、数组等处理方法:解构

    对象方法简写 你可以在定义方法时省略function和 :: const obj = { insteadOfThis: function() { // do stuff }, youCanDoThis ...

  9. zabbix分布式监控服务 安装与配置

    zabbix安装与配置   一.什么是zabbix及优缺点(对比cacti和nagios) Zabbix能监视各种网络参数,保证服务器系统的安全运营:并提供灵活的通知机制以让系统管理员快速定位/解决存 ...

  10. border-radius:50%和100%的区别

    border-radius 值类型-百分比 border-radius的值是百分比的话,就相当于盒子的宽度和高度的百分比. 我们知道在一个正方形内做一个面积最大的圆形,这个圆的半径就为正方形边长的一半 ...