
多线程及并发编程
文章平均质量分 65
多线程相关和并发编程
WannaRunning
这个作者很懒,什么都没留下…
展开
-
Caffeine缓存
目录Caffeine相关参数缓存大小过期策略填充策略Caffeine框架中Cache的使用同步需要手动维护——Cache同步可设置缓存自动触发加载——LoadingCache异步需手动维护——AsyncCache异步可设置缓存自动触发加载——AsyncLoadingCache在本地(进程)缓存方面,常见的环框框架有ehcache、GuavaCache、Caffeine等方案。Caffeine是其中性能最好的一个。Caffeine相关参数缓存大小使用max原创 2022-01-02 16:25:37 · 5187 阅读 · 0 评论 -
浅谈Netty中的FastThreadLocal的优势和实现
基于FastThreadLocalThread去使用FastThreadLocal时的效率要高于JDK的Thread使用ThreadLocal。FastThreadLocal为什么比ThreadLocal快FastThreadLocal与ThreadLocal内部存储结构不同,FastThreadLocal基于数据的存储形式,相对ThreadLocal来说站空间多,但是却使得查找效率更高,而ThreadLocal基于hash表,当存在Hash冲突时基于线性表的查找效率显然不如数组索引查找。Thr原创 2021-10-30 16:52:06 · 376 阅读 · 0 评论 -
ConcurrentLinkedQueue和LinkedBlockingQueue
首先二者都是线程安全的队列。LinkedBlockingQueueLinkedBlockingQueue是阻塞队列,其阻塞是基于ReentrantLock锁机制实现的。阻塞队列中元素的存取是支持阻塞的。当队列为空时,获取元素方法会阻塞等待有元素存入后再获取元素返回;如果队列设置了大小,队列满时无法存放,存放元素方法会阻塞等待有空位时再存放。offer()基于ReentrantLock锁机制存放元素,该方法是阻塞的,如果queue设置了大小且当前已经满了,则方法会阻塞等待有空位置是存放元素原创 2021-10-15 16:54:15 · 1347 阅读 · 0 评论 -
ConcurrentHashMap在并发场景下使用的优化实践
背景按门店分类存储订单信息,维护在一个ConcurrentHashMap<String,ConcurrentLinkedQueue>的结构中,实际业务中存在并发。所以功能的实现要考虑从map结构中取值操作关于value的非空判断和初始化操作的并发安全问题。功能实现可以忽略从Map取出ConcurrentLinkedQueue队里和往队列放订单这两步操作的原子性,业务中允许订单顺序存在一定误差。第一版代码实现之前有文章写过ConcurrentHashMap并发场景下的使用方式,可以原创 2021-09-29 00:55:16 · 1298 阅读 · 0 评论 -
使用ConcurrentHashMap就不需要加锁了么
问:HashMap不是线程安全的,那多线程中可以使用什么代替呢?这个问题想必都会回答,使用ConcurrentHashMap。但是,使用了ConcurrentHashMap就意味着任何操作都不需要加锁就能保证线程安全么?其实不是这样的,ConcurrentHashMap的线程安全指的是ConcurrentHashMap中的put,get方法是线程安全的,也就是说在使用这两个方法时不需要额外加锁。但是这并不意味着其他使用到ConcurrentHashMap的地方都不需要加锁。例如下面的代码:j原创 2021-09-07 21:01:19 · 3857 阅读 · 1 评论 -
高并发库存系统设计——订单流转过程中的库存操作
什么环节占用库存通常在提交订单时占用库存较为合理。 如果再提交订单之后,支付前占用库存就会出现库存不足支付失败的情况,在用户体验上明显不合理。库存占用功能设计思路redis + mq + mysql 实现高并发减库存操。把商品的可售卖库存做缓存例如Redis,在提交订单时基于Redis缓存的可售卖库存做库存是否充足的校验和减库存操作,然后通过发送MQ即异步的方式在消费端执行数据库中得减库存操作。根据订单中商品数量扣减redis中缓存的可售卖库存,扣减时如果没有缓存则回源DB查询门店.原创 2021-07-02 00:53:32 · 628 阅读 · 0 评论 -
业务系统二级缓存的设计使用
在有些业务里例如用餐高峰期产品信息的数据在高并发下就会存在问题,难以给予稳定的服务支持,常出现服务请求超时的情况。这种数据量大且并发访问量高的场景就可以通过多级缓存来提高服务的稳定性。二级缓存的设计一级缓存可以使用服务本地缓存,像EhCache,Guava 或者Caffeine等 二级缓存使用Redis等中间件。二级缓存的实现思路如果本地缓存开关开启则从一级缓存中获取,命中直接返回,未命中进行下一步。 如果二级缓存(如redis缓存)开启则从二级缓存去读数据,如果redis缓存命.原创 2021-07-01 20:07:34 · 1364 阅读 · 0 评论 -
多线程下集合类的选用
ArrayList,HashMap都是非线程安全的类,因此在多线程中不能使用。那么多线程下如果要使用集合或map类型怎么办呢?当然是有别的替代类,比如HashMap要选用HashTable或ConcurrentHashMap,而ArrayList则要选用Vector或CopyOnWriteArrayList。HashTable和ConcurrentHashMap两者的区别就是HashTable是完全基于synchronized锁实现的同步,而ConcurrentHashMap则是CAS+vola原创 2020-12-28 17:13:46 · 632 阅读 · 0 评论 -
浅谈java内存模型和volatile可见性实现原理
之前的文章写了volatile关键字特点及AtomicInteger类的实现,这篇文章分析一下volatile为什么能保证变量在多线程间的可见性。JMM中变量操作的方式在java内存模型中,为了提高处理器的执行速度,规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行原创 2021-01-18 14:35:50 · 221 阅读 · 0 评论 -
多线程之ConcurrentHashMap的实现
DK 1.7 中使用分段锁(ReentrantLock + Segment + HashEntry),相当于把一个 HashMap 分成多个段,每段分配一把锁,这样支持多线程访问。锁粒度:基于 Segment,包含多个 HashEntry。 Segment 继承 ReentrantLock(重入锁)用来充当锁的角色,每个 Segment 对象守护每个散列映射表的若干个桶;HashEntry 用来封装映射表的键-值对;每个桶是由若干个 HashEntry 对象链接起来的链表 ...原创 2021-04-02 15:48:54 · 727 阅读 · 1 评论 -
synchronized锁的级别和ReentrantLock锁(AQS)
针对并发JAVA中提供了JVM级别的synchronized关键字,除此之外在JUC包下Lock接口也提供了类似的锁机制,例如ReentrantLock可重入锁。synchronizedJVM的关键字,依靠底层机制实现的。synchronized 中的锁是非公平的; synchronized 中的锁是可重入的;ReentrantLockReentrantLock 是 JDK 实现的,在java.util.concurrent.locks 包下。实现方式:ReentrantLo.原创 2021-01-20 16:29:00 · 1293 阅读 · 0 评论 -
干扰线程执行的前后顺序——Thread类的join方法
经常听到这样一个面试题:如何保证多个线程的执行顺序?答案有很多,比如使用CompletableFuture(JDK8新增),LookSupport工具类,wait和notify,还有这篇文章要写的Thread.join() 方法Thread类的 join() 方法可以阻塞当前的线程,假设线程A中执行调用了线程B的join方法,那在线程B执行完之前,A线程是无法继续往下执行的,需要注意的是 等待调用了join() 方法的线程执行完后再执行,所以使用时不能自己调用自己的join方法,这样会导致线程自身原创 2021-03-20 16:51:43 · 347 阅读 · 1 评论 -
服务器CPU高占用和JVM内存泄漏排查
jstack命令jstack能得到运行java程序的java stack和native stack的信息,可以轻松得知当前线程的运行情况。CPU占用100%分析思路是找到进程,进而找到占用CPU的线程。1.找到 cpu 占有率最高的 java 进程号top -c显示运行中的进程列表信息,shift + p使列表按 cpu 使用率排序显示top -c2.根据进程号找到 cpu 占有率最高的线程号,把线程的PID由 十进制 转成 十六进制。使用命令:top -Hp {.....原创 2021-03-08 18:07:08 · 326 阅读 · 0 评论 -
ReentrantReadWriteLock实现原理
之前写了synchronized和基于AQS实现的ReentrantLock,这篇文章写一下与ReentrantLock类似的ReentrantReadWriteLock。ReentrantReadWriteLock和ReentrantLock一样都在java.util.concurrent包下,通常我们使用ReentrantReadWriteLock的两个内部类ReadLock和WriteLock即读锁和写锁来实现更细粒度的同步功能,读写锁的实现也是基于AQS和CAS实现的,分别用的就是AQS的共原创 2021-01-21 15:54:59 · 202 阅读 · 0 评论 -
CAS原子操作之AtomicStampedReference
java.util.concurrent.atomic包中提供了AtomicBoolean,AtomicInteger,AtomicLong等常见类型的类,这些类通过CAS实现了原子操作,但是这些类都是只针对单一类型的单一变量保证原子操作。如果需要对多个变量同时操作,AtomicReference这个类通过指定泛型的方式可以实现对JAVA类进行原子操作。需要注意的是这些类中都存在ABA问题。AtomicStampedReferenceAtomicStampedReference其实和AtomicRe原创 2021-01-25 10:47:19 · 396 阅读 · 1 评论 -
ThreadPoolTaskExecutor实现多线程并处理返回值
这篇文章主要记录一下有返回值的多线程该怎么实现。之前的文章有提到过ThreadPoolTaskExecutor线程池执行任务有几个方法:executor.execute(Runnable task):完美适用于没有返回值的情况。未捕获的异常会抛出executor.submit(Runnable task):也适用于没返回值的情况,未捕获的异常不会抛出executor.submit(...原创 2019-12-12 17:29:39 · 6540 阅读 · 0 评论 -
JAVA使用自定义异常的优化——重写fillInStackTrace方法
最近在看性能优化相关的东西,就看到了关于自定义业务异常的使用,观点是不建议,如果一定要使用,在不需要知道异常堆栈信息的情况下必须重写Throwable的fillInStackTrace()方法,这个方法是native修饰即JVM本地同步方法,native实现是将线程的栈帧信息记录到此 Throwable 对象中,也就是我们看到的发生在哪个类的哪一行代码处等信息。其实开发中很多时候为了省事都直接在Service层直接抛业务异常,controller捕获业务异常封装结果,至少有时候我是这么写的。这种情况建议原创 2021-03-07 15:07:06 · 1520 阅读 · 1 评论 -
ThreadLocal
在多线程并发情况下,有一个共享变量,不同线程设置不同值后,各线程只想获取自己设置的值,如何实现?使用ThreadLocal,通过ThreadLocal实例对象的set方法设置各线程自己的值,通过ThreadLocal实例对象的get方法获取各线程自己设置的值。ThreadLocal实现原理分析set方法的实现逻辑,如果getMap方法获取的ThreadLocalMap类型变量map不等于null,则以当前ThreadLocal对象为key,传入的value值为value存到这个ThreadLoc原创 2020-11-09 17:56:17 · 128 阅读 · 0 评论 -
LockSupport的park/unpark对比wait/notify
wait/notify是Object的方法,且这两个方法必须与synchronized同时使用,否则会抛出IllegalMonitorException。而LockSupport无需加锁,直接调用其静态方法park就可以使当前线程进入阻塞状态。Object中wait和notify方法必须要按顺序调用,如果因为线程调度问题导致线程A先调用notify方法而线程B后调用wait方法,那么会使线程A永远处于WAIT状态,形成死锁。...原创 2021-02-03 16:55:40 · 307 阅读 · 0 评论 -
TaskDecorator——异步多线程中传递上下文等变量
目录TaskDecorator定义TaskDecorator实例线程池使用TaskDecorator开发中很多数据如oauth2的认证信息,日志TracerId都是在请求线程中的,如果内部使用多线程处理就存在获取不到认证信息或TraceId的问题。这时候就需要处理子线程与主线程间数据传递的问题。TaskDecorator这个问题需要使用线程的ThreadLocal和TaskDecorator来处理。官方文档中描述意思是TaskDecorator是一个执行回调方法的装饰器,主要应用于传原创 2020-12-17 11:38:26 · 16739 阅读 · 9 评论 -
基于@EnableAsync使用线程池实现多线程
相对于传统编码的方式使用多线程,在SpringBoot中提供了基于注解的更简单的实现方式:基于@EnableAsync和@Async注解配置:项目使用@EnableAsync开启异步,使用@Async 注解在service内的方法上,这样在controller层直接调用service方法时,可以实现@Async注解的方法在单独线程内运行,实现controller层调用service后即时返回,service方法异步处理的效果。一般会在@Async上注明使用的线程池。@Async 注解的方法要么就原创 2020-12-16 18:17:45 · 1194 阅读 · 1 评论 -
ThreadPoolExecutor和ThreadPoolTaskExecutor线程池
在非SpringBoot项目中一般是通过xml配置一个线程池的Bean,然后注入bean进而使用线程池执行任务。java开发中使用的线程池一般是ThreadPoolTaskExecutor和ThreadPoolExecutor两个,前者是spring提供的,后者是JDK自带的。贴一下使用spring的ThreadPoolTaskExecutor线程池的Bean配置<!-- sp...原创 2019-12-01 00:11:59 · 977 阅读 · 0 评论 -
线程基础和多线程创建
进程 : 正在执行的程序称作为一个进程。 进程负责了内存空间的划分。线程: 线程在一个进程 中负责了代码的执行,就是进程中一个执行路径,多线程: 在一个进程中有多个线程同时在执行不同的任务。线程负责了代码 的执行,我们之前没有学过线程,为什么代码可以执行? 运行任何一个java程序,jvm在运行的时候都会创建一个main线程执行main方法中所有代码。一个java应用程序至少有两个线程, 一...原创 2018-06-13 16:54:16 · 401 阅读 · 0 评论