CAS

解析 Callable Runnable Future 使用和原理

感情迁移 提交于 2020-02-28 13:37:28
概念 Callable类的定义 @FunctionalInterface public interface Callable<V> { V call() throws Exception; } Runnable类的定义 @FunctionalInterface public interface Runnable { public abstract void run(); } Future类的定义 public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } Callable Runnable Future 都是为异步执行设计的接口类。Callable与Runnable接口的区别是Callable有返回值,并且会抛出异常信息,Runnable没有返回值,也不允许抛出异常

ConcurrentHashMap

女生的网名这么多〃 提交于 2020-02-28 13:01:45
1、ConcurrentHashMap有哪些构造函数? 一共有五个,作用及代码如下: // 无参构造函数 public ConcurrentHashMap() { } // 可传初始容器大小的构造函数 public ConcurrentHashMap( int initialCapacity) { if (initialCapacity < 0 ) throw new IllegalArgumentException(); int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1 )); this .sizeCtl = cap; } // 可传入map的构造函数 public ConcurrentHashMap(Map<? extends K, ? extends V> m) { this .sizeCtl = DEFAULT_CAPACITY; putAll(m); } // 可设置阈值和初始容量 public ConcurrentHashMap( int initialCapacity, float loadFactor) { this

使用redis提升消息幂等性能

荒凉一梦 提交于 2020-02-28 08:19:27
使用redis提升消息幂等性能 一、 消息幂等 由于网络可靠性的原因不能保证消息必达,那么必须使用补偿机制重新发送消息。多次发送消息必须保证消费者只会消费一次,那么就需要保证实现接口的幂等性。 二 、架构思路 2.1 幂等实现思路 状态机:利用数据库业务表状态CAS操作保证幂等性 消息去重表:根据业务id生成唯一消息id和数据库唯一约束 唯一业务id:利用上游业务id结合数据库唯一约束 2.2 通用策略 从上述的方法中,通用策略且方便做无侵入操作的是消息去重表方案。 三、 落地方案 自定义注解 + AOP切面方案,步骤: 切面拦截到有@UnqMsg注解的消息监听类的方法 首先查看redis.exist是否存在消息id 存在信息则获取消息返回执行成功 不存在则预写入消息去重表中,不提交事务,待业务方操作数据写入后,统一提交。 应注意几个要点: 如果分库分表必须做好路由配置 消费方如果没有RMDB入库的提交操作怎么保证一致性,可以让业务方自己实现逻辑入库消息去重表 redis和RMDB数据数据同步操作,使用canal组件同步数据到redis中,提升消息去重表查询效率,value = 1,过期时间根据业务需求定,3D、5D、7D。 消息去重表的过期数据处理,可以定时清空。 来源: oschina 链接: https://my.oschina.net/teddyIH/blog

JAVA中相关原子操作详解

白昼怎懂夜的黑 提交于 2020-02-28 07:55:15
Java中的原子操作类详解 Java中的原子操作类详解 1、原子更新基本类型类 2、原子更新数组 3、原子更新引用类型 4、原子更新字段类 5、CAS算法 6、ABA问题 当更新一个变量时,如果多线程同时更新这个变量,为了保证多线程不会更新这个变量,一般使用关键字synchronized来保证多线程不会同时修改该变量。 jdk1.5后,java.util.concurrent.atomi包下提供了更简洁,高效和安全的原子操作类: 1、原子更新基本类型类 AtomicInteger:整型原子类 AtomicLong:长整型原子类 AtomicBoolean :布尔型原子类 AtomicInteger 类主要利用 CAS (compare and swap) + volatile 和 native 方法来保证原子操作,从而避免synchronized 的高开销,执行效率大为提升。 CAS的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。UnSafe 类的objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外 value 是一个volatile变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。 源码: // setup to use Unsafe.compareAndSwapInt for

多线程——系列三 java锁

喜你入骨 提交于 2020-02-28 04:56:35
乐观锁 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为 别人不会修改,所以不会上锁,但是 在更新的时候会判断一下在此期间别人有没有去更新这个数 据,采取在写时先读出当前版本号,然后加锁操作 (比较跟上一次的版本号,如果一样则更新), 如果失败则要重复读-比较-写的操作。 java 中的乐观锁基本都是通过 CAS 操作实现的,CAS 是一种更新的原子操作, 比较当前值跟传入 值是否一样,一样则更新,否则失败 。 悲观锁 悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人 会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会 block 直到拿到锁。 java中的悲观锁就是 Synchronized ,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到, 才会转换为悲观锁,如 RetreenLock。 自旋锁 自旋锁原理非常简单, 如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁 的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋), 等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗 。 线程自旋是需要消耗 cup 的,说白了就是让 cup 在做无用功,如果一直获取不到锁,那线程 也不能一直占用 cup 自旋做无用功

深入理解JVM

浪子不回头ぞ 提交于 2020-02-28 04:51:12
如果下面的一些概念有些不清楚的可以先看 深入理解JVM - 垃圾收集器 。 Shenandoah是一款只有OpenJDK才会包含的收集器,最开始由RedHat公司独立发展后来贡献给了OpenJDK,相比G1主要改进点在于: 支持并发的整理算法,Shenandoah的回收阶段可以和用户线程并发执行; Shenandoah 目前不使用分代收集,也就是没有年轻代老年代的概念在里面了; Shenandoah 摒弃了在G1中耗费大量内存和计算资源去维护的记忆集,改用名为“连接矩阵”(Connection Matrix)的全局数据结构来记录跨Region的引用关系,降低了处理跨代指针时的记忆集维护消耗,也降低了伪共享问题的发生概率。 Shenandoah收集器的工作过程 Shenandoah收集器的工作过程一共有九个阶段,下图只画了最核心的三个阶段并发标记、并发回收、并发引用更新。 初始标记(Initial Marking) :与G1一样,只标记与GC Roots直接关联的对象,这个阶段仍是“Stop The World”的,但停顿时间与堆大小无关,只与GC Roots的数量相关。 并发标记(Concurrent Marking) :与G1一样,从GC Root开始对堆中对象进行可达性分析,找出存活的对象,可与用户线程并发执行,不会造成停顿

ThreadPoolExecutor 线程池"源码分析"

杀马特。学长 韩版系。学妹 提交于 2020-02-28 04:17:29
ThreadPoolExecutor 线程池源码分析 白牙想说 很久没更新了,原因并不是没有学习,而是学完了不知道怎么写出来,同时还有一股声音在耳边告诉我,现在公众号满天飞,写公众号的人比看公众号多,同 topic 的文章太多了......。但后面我自己想通了,虽然类似的文章很多,但它不是我写的,自己写完有助于对相关知识的梳理,如果刚好能给大家带来一些帮助,那就更好了,所以白牙还是鼓励大家多输出,通过输出倒逼输入,其中的收获只有做了才知道 ThreadPoolExecutor 类图 通过类图可知,ThreadPoolExecutor 是一个 ExecutorService,可以通过池中的线程来执行任务 常用属性 // 线程池中重要的变量 ctl,类型为 AtomicInteger,一个变量同时记录线程池状态和线程个数 // Integer 的位数为 32 位,其中高 3 位表示线程池的状态,低 29 位表示线程的个数。默认为 RUNNING 状态,线程个数为 0 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // 线程个数掩码位数,去掉高 3 位代表线程个数的 bit 位 private static final int COUNT_BITS = Integer.SIZE - 3; /

Java中的各种锁

南楼画角 提交于 2020-02-28 03:52:16
转自公众号Java建设者 ,作者cxuan Java 锁分类 Java 中的锁有很多,可以按照不同的功能、种类进行分类,下面是我对 Java 中一些常用锁的分类,包括一些基本的概述 https://www.javashitang.com/wp-content/uploads/2020/01/beepress8-1578910007.jpg 从线程是否需要对资源加锁可以分为 悲观锁 和 乐观锁 从资源已被锁定,线程是否阻塞可以分为 自旋锁 从多个线程并发访问资源,也就是 Synchronized 可以分为 无锁、偏向锁、 轻量级锁 和 重量级锁 从锁的公平性进行区分,可以分为公平锁 和 非公平锁 从根据锁是否重复获取可以分为 可重入锁 和 不可重入锁 从那个多个线程能否获取同一把锁分为 共享锁 和 排他锁 下面我们依次对各个锁的分类进行详细阐述。 线程是否需要对资源加锁 Java 按照是否对资源加锁分为乐观锁和悲观锁,乐观锁和悲观锁并不是一种真实存在的锁,而是一种设计思想,乐观锁和悲观锁对于理解 Java 多线程和数据库来说至关重要,下面就来探讨一下这两种实现方式的区别和优缺点 悲观锁 悲观锁是一种悲观思想,它总认为最坏的情况可能会出现,它认为数据很可能会被其他人所修改,所以悲观锁在持有数据的时候总会把资源 或者 数据 锁住,这样其他线程想要请求这个资源的时候就会阻塞

CAS 原子操作

别来无恙 提交于 2020-02-28 03:27:34
所谓原子操作类,指的是java.util.concurrent.atomic包下,一系列以Atomic开头的包装类。例如 AtomicBoolean , AtomicInteger , AtomicLong 。它们分别用于 Boolean , Integer , Long 类型的原子性操作。 private static AtomicInteger count = new AtomicInteger ( 0 ) ; public static void main ( String [ ] args ) { for ( int i = 0 ; i < 2 ; i ++ ) { new Thread ( new Runnable ( ) { @ Override public void run ( ) { try { Thread . sleep ( 10 ) ; } catch ( Exception e ) { e . printStackTrace ( ) ; } //每个线程让count自增100次 for ( int i = 0 ; i < 100 ; i ++ ) { count . incrementAndGet ( ) ; } } } ) . start ( ) ; } try { Thread . sleep ( 2000 ) ; } catch (