前面 使用自旋锁实现了一把锁,(请看 第5篇)

volatile 三大特性: 可见性, 不保证原子性, 禁止指令重排

为了解决 volatile不保证原子性的问题, 引入了原子类, AtomicInteger, 底层是使用了 CAS 直接变成汇编指令操作硬件,从而解决了 原子性的问题

而 Lock 类的底层实现是 AQS 和CAS,

这里使用 AtomicInteger的特性和自旋锁来实现一把 排队自旋锁 锁:

  class AtomicLock {
private AtomicInteger serviceNum = new AtomicInteger();//等待者
private AtomicInteger ticketNum = new AtomicInteger();//排队号 public int atomicLock() {
// 排队号加1
int myTicketNum = ticketNum.getAndIncrement();
//只要 排队号和 等待着的号不同,等待者就一直循环, 如果相同,就返回排队号, 这里相当于加锁成功
while (serviceNum.get() != myTicketNum) {
}
System.out.println(Thread.currentThread().getName() + "加锁成功");
return myTicketNum;
} public void atomicUnlock(int num) {
// 如果要解锁,就将排队号 +1, 并设置回等待者
int next = num + 1;
serviceNum.compareAndSet(num, next);
System.out.println(Thread.currentThread().getName() + "解锁成功");
} static int num = 0;
public static void main(String[] args) throws InterruptedException {
/**
* 这个锁的缺点是: 如果线程很多, 这么多线程都要操作 同一个Atomicinteger, 且为了保证 各个线程的工作缓存中的数据一致性,
* 会频繁的 在工作缓存和 主存之间进行通信,,造成系统总线和主存之间繁重的流量, 进而降低系统的性能
*
* 但是多处理器系统上,每个进程/线程占用的处理器都在读写同一个变量serviceNum ,每次读写操作都必须在多个处理器缓存之间进行缓存同步,
* 这会导致繁重的系统总线和内存的流量,大大降低系统整体的性能。
* 如何解决: 使用 CLH锁和MCS锁
*/
AtomicLock atomicLock = new AtomicLock();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
int j = atomicLock.atomicLock();
System.out.println(Thread.currentThread().getName() + "操作开始: num: " + num);
for (int k = 0; k < 20; k++) {
num++;
}
System.out.println(Thread.currentThread().getName() + "操作结束: num: " + num);
atomicLock.atomicUnlock(j);
},"线程"+i).start();
} TimeUnit.SECONDS.sleep(3);
System.out.println("最终结果num: "+num);
}
}

运行结果:



CLH锁和 MCS锁, 这个是目前写的比较好的博客

https://www.jianshu.com/p/1b1b44e84394

JUC 并发编程--12, 使用AtomicInteger 实现一把锁(排队自旋锁), 代码演示的更多相关文章

  1. Java并发编程:用AQS写一把可重入锁

    Java并发编程:自己动手写一把可重入锁详述了如何用synchronized同步的方式来实现一把可重入锁,今天我们来效仿ReentrantLock类用AQS来改写一下这把锁.要想使用AQS为我们服务, ...

  2. Java并发编程:自己动手写一把可重入锁

    关于线程安全的例子,我前面的文章Java并发编程:线程安全和ThreadLocal里面提到了,简而言之就是多个线程在同时访问或修改公共资源的时候,由于不同线程抢占公共资源而导致的结果不确定性,就是在并 ...

  3. JUC 并发编程--06, 阻塞队列(7种), 阻塞等待 api的 代码验证

    这些队列的 api ,就是添加队列,出队列,检测对首元素, 由于 add()--remove(), offer()--poll(),太简单这里不做验证, 只验证后二组api: 阻塞等待( put()- ...

  4. JUC并发编程学习笔记

    JUC并发编程学习笔记 狂神JUC并发编程 总的来说还可以,学到一些新知识,但很多是学过的了,深入的部分不多. 线程与进程 进程:一个程序,程序的集合,比如一个音乐播发器,QQ程序等.一个进程往往包含 ...

  5. 并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性

    Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...

  6. JUC并发编程基石AQS之主流程源码解析

    前言 由于AQS的源码太过凝练,而且有很多分支比如取消排队.等待条件等,如果把所有的分支在一篇文章的写完可能会看懵,所以这篇文章主要是从正常流程先走一遍,重点不在取消排队等分支,之后会专门写一篇取消排 ...

  7. 漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼?(转)

    知乎链接:https://zhuanlan.zhihu.com/p/57354304 1. 锁的由来? 学习linux的时候,肯定会遇到各种和锁相关的知识,有时候自己学好了一点,感觉半桶水的自己已经可 ...

  8. JUC并发编程与高性能内存队列disruptor实战-上

    JUC并发实战 Synchonized与Lock 区别 Synchronized是Java的关键字,由JVM层面实现的,Lock是一个接口,有实现类,由JDK实现. Synchronized无法获取锁 ...

  9. JUC并发编程基石AQS源码之结构篇

    前言 AQS(AbstractQueuedSynchronizer)算是JUC包中最重要的一个类了,如果你想了解JUC提供的并发编程工具类的代码逻辑,这个类绝对是你绕不过的.我相信如果你是第一次看AQ ...

随机推荐

  1. Hydra暴力破解工具的用法

    目录 Hydra 常见参数 破解SSH 破解FTP 破解HTTP 破解3389远程登录 Kali自带密码字典 dirb dirbuster fern-wifi metasploit wfuzz Hyd ...

  2. 使用Layui、Axios、Springboot(Java) 实现EasyExcel的导入导出(浏览器下载)

    实现EasyExcel的导入导出(浏览器下载) 实现三个按钮的功能,但是却花费了一天的时间包括总结. 使用到的技术:springboot layui axios EasyExcel mybatis-p ...

  3. Jedis基础详解

    Jedis 使用Java来操作Redis 什么是Jedis 是Redis官方推荐的Java操作Redis中间件, 如果你要使用Java操作Redis, 那么就该对jedis熟悉 测试 导入对应的依赖 ...

  4. 大数据开发-Flink-数据流DataStream和DataSet

    Flink主要用来处理数据流,所以从抽象上来看就是对数据流的处理,正如前面大数据开发-Flink-体系结构 && 运行架构提到写Flink程序实际上就是在写DataSource.Tra ...

  5. UA: Literally Vulnerable靶机

    前言 略有点虎头蛇尾.主要有一步没想通. web打点 nmap -sP 192.168.218.0/24 #发现主机IP 192.168.218.138 #端口扫描 nmap -sV -p- 192. ...

  6. InnoDB存储引擎简介

    前言: 存储引擎是数据库的核心,对于 MySQL 来说,存储引擎是以插件的形式运行的.虽然 MySQL 支持种类繁多的存储引擎,但最常用的当属 InnoDB 了,本篇文章将主要介绍 InnoDB 存储 ...

  7. 什么是redis的缓存雪崩, 穿透, 击穿?

    目前的互联网系统没有几个不使用缓存的, 但是只要使用缓存的话就会面临这几个问题, 如使用redis缓存技术, 可能会遇到缓存的雪崩, 穿透, 以及击穿. 首先来看一个简单的正常缓存流程: 如用户访问J ...

  8. Java_接口回调与匿名内部类

    匿名内部类 警告:匿名内部类本质上是一个对象 如果有一个接口或者抽象类,必须要用class定义一个实现类写重写抽象方法,才能创建对象并使用. 匿名内部类就是省略了用class定义子类的过程,直接使用父 ...

  9. linux下符号链接和硬链接的区别

    存在2众不同类型的链接,软链接和硬链接,修改其中一个,硬链接指向的是节点(inode),软链接指向的是路径(path) 软连接文件 软连接文件也叫符号连接,这个文件包含了另一个文件的路径名,类似于wi ...

  10. 3D深色金属哥特3D项目工具小图标icon高清设计素材

    3D深色金属哥特3D项目工具小图标icon高清设计素材