自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(231)
  • 收藏
  • 关注

原创 reentrantLock

重入的概念是什么,实现原理是什么?公平锁和非公平锁区别是什么,体现在哪些地方?没有竞争到锁的线程怎么实现等待,释放锁时又是怎么被唤醒的?发现没有是不是跟synchronized代码结构差不多,只是多了一个lock和unlock的过程。我们先画个图来对比一下synchronized和lock的数据结构:这就是学技术特别有趣的地方,你看多了感觉很多高大上的技术底层设计实际都差不多。ReentrantLock默认是非公平锁。

2022-09-14 13:45:07 393

原创 CountDownLatch、CyclicBarrier、semaphore

CountDownLatch中调用await方法线程需要等待所有调用countDown方法的线程执行,这就很适合一个业务需要一些准备条件,等准备条件准备好之后再继续执行,如果一些复杂的聚合查询,还有一些类似于广播消息的功能。

2022-09-13 14:53:59 1355

原创 零拷贝、MMAP、堆外内存

原理:是一种内存映射文件的方法, 可以将一个文件或者其他对象映射到进程的虚拟地址空间,实现文件磁盘地址和进程虚拟地址空间中某一段地址的一一对应,这样应用程序就可以通过访问进程虚拟内存地址直接访问文件,进而达到操作文件的目的,这样就不用拷贝数据到用户态后再操作了。第三次数据拷贝:用户进程调用send()方法期望将数据发送到网络中,此时用户态会再次切换到内核态,请求的数据从用户态缓冲区被拷贝到Socket缓冲区。第二次数据拷贝:请求的数据从内核态缓冲区拷贝到用户态缓冲区,然后返回给用户进程。

2022-09-13 14:51:52 558 1

原创 ThreadLocal

ThreadLocal实际上是通过Thread的成员变量threadLocals来发挥作用,ThreadLocal对象作为key,设置的值作为value放入threadLocals中,所以你如果使用了ThreadLocal那么当前线程就会使用threadLocals变量持有你设置值的threadlocal对象和这个threadLocal设置的值当你用threadLocal对象get方法获取值时就会通过threadLocals变量的map获取这个threadLocal设置的值。

2022-09-13 10:35:15 232

原创 scheduledThreadPool

怎样做到每个任务延迟指定时间执行?内部使用了什么数据结构保存延迟任务?延迟任务放入scheduledThreadPool时机并不固定,怎么保证按延迟时间顺序执行?

2022-09-12 16:29:41 490

原创 CachedThreadPool

corePoolSize是0,maximumPoolSize是Integer.MAX_VALUE,根据我们之前对源码的分析,CachedThreadPool不会有核心线程,核心线程数的addworker方法不会执行,直接尝试加入queue中。keepAliveTime是60s,也就是60s从队列中没有拿到任务,worker就会自动销毁,销毁过程在fixed的分析中已经看过了。

2022-09-12 16:08:41 2540

原创 FixedThreadPool

newFixedThreadPool实际上返回的是ThreadPoolExecutor,ThreadPoolExecutor实际就是线程池实现类,使用了典型的模板方法设计模式,通过ThreadPoolExecutor构造器的说明我们稍微解释一下各参数的意思:corePoolSize 核心线程数,线程池一直存在的线程(即使这些线程是空闲的),除非你设置allowCoreThreadTimeOut。

2022-09-12 15:50:44 2988

原创 ArrayBlockingQueue

记得LinkedBlockingQueue使用的AtomiInteger,而这里直接使用了int,这是因为LinkedBlockingQueue使用的两把锁,put和take互不干扰,所以count有多线程操作,而ArrayBlockingQueue使用的是一把锁,put和take互斥。说明元素此时已经放过数组一轮的位置了,而且通过之前的判断,现在元素的数量是没有达到数组长度的,所以数组前面的元素肯定有被take的,所以此时应该重新开始放元素。同一个作者写的,为什么会写出两个逻辑,不是很理解。

2022-09-12 15:32:08 440

原创 ConcurrentHashMap解析

在初始化数组时使用cas保证只有一个线程能成功并去做初始化工作,其他线程则继续for循环在没有hash冲突时tab[i]使用cas进行赋值,保证同时只有一个线程赋值成功,其他线程则在下次for循环时进入hash冲突的代码段当有hash冲突时使用synchronized锁住tab[i]位置的元素,而且进行了双检查,保证上锁后元素没有变化,然后在锁里进行链表或红黑树的维护,保证了hash冲突时元素的插入也是线程安全的。

2022-09-12 15:30:21 329

原创 ConcurrentLinkedQueue解析

add过程实际就是不停就是在单链表不断挂新元素的过程,挂next元素时使用了cas来保证线程的安全性,而且不是每次add都会移动tail指针,而是tail已经不是现在的最后一个node时才会移动tail指针。

2022-09-12 15:04:53 7023 1

原创 CopyOnWriteArrayList解析

CopyOnWriteArrayList是ArrayList多线程安全的一种实现,底层都是用数组来实现,但CopyOnWriteArrayList在add,remove,set等修改操作使用lock来保证修改的线程安全。但是读操作和集合的遍历并没有使用锁,可能会存在读写不一致的情况。

2022-09-12 12:07:34 293

原创 LinkedBlockingQueue源码分析

在put元素时,首先拿到的putLock重入锁,而且记录元素个数的count也是AtomicInteger,保证了count累加的线程安全性LinkedBlockingQueue的node节点、head、tail,next等都没有使用volatile修饰,而且挂新节点也没有ConcurrentLinkedQueue那么复杂的自旋和判断,所以这就是锁带来的一个好处(或者说是锁粒度带来的好处,粒度越小可能存在的线程安全问题越多),代码复杂度会大大降低,各种多线程下写失败的情况就不会出现,

2022-09-12 11:38:47 108

原创 TreeMap和LinkedHashMap

底层是基于红黑树实现,是个有序集合,按照key的compareTo方法或在构造时传入的Comparator比较器进行排序。这里需要注意如果在构造 时没有传入Comparator,那么key必须实现Comparable接口,不然会报错TreeMap是通过Comparator比较器来构建红黑树从而保证key的有序性,而LinkedHashMap是通过双向链表来保证元素插入的有序性,两者有序性的含义不是一样的。

2022-09-12 11:18:34 1657

原创 HashMap的put源码解析

hashMap的put方法解析

2022-09-12 10:57:14 153

原创 HashMap源码面试题

总体特点:java1.8之前使用的是数组+单向链表的数据结构,java1.8及之后使用的是数组+单向链表+红黑树的数据结构,在hash冲突形成的单向链表元素个数达到8个时会转成红黑树。使用无参构造器初始化的node数组容量是16(在resize()方法中初始化),加载因子是0.75(也就是说当node数组中元素超过0.75容量时会进行扩容),扩容时新容量是旧容量的2倍。扩容时java1.8之前使用的头插法,头插法可能会导致元素的丢失、hash环等问题,java1.8及之后使用的是尾插法,能够避免之前

2022-04-05 13:42:50 575

原创 java源码之LinkedList

LinkedList优点:基于双向链表实现,增删改的效率很高可以当队列来用LinkedList缺点:链表的遍历时间复杂度是O(n),所以随机读是非常慢的LinkedList使用场景:LinkedList在生产中使用较ArrayList少很多,因为一般程序都是读多写少,LinkedList却更适合写多读少的情况。LinkedList主要方法解析:add(E e):在双向链表尾部插入一个元素生成指针l指向双向链表中的最后一个元素last生成一个新的node节点,pre是last,next是

2022-04-04 17:22:59 421

原创 ArrayList源码

ArrayList优点:随机读性能很高,因为底层是基于数组实现,可以通过get(i)寻址快速读取获取元素个数性能很高arrayLis天生按元素插入顺序排序ArrayList缺点:在扩容时需要从旧数组把元素拷贝到新数组,性能很差在随机插入时会导致插入点之后的元素在数组中移动,性能也很差ArrayList使用场景及使用注意事项:在new ArrayList时最好根据业务场景进行容量的初始化,避免在之后的Add操作时触发数组的扩容,进而提高使用性能如果有频繁的add(i,e)的操作则不建议使用

2022-04-04 15:57:08 515

原创 微服务架构的演进

1.典型的微服务架构应该至少包括下图组件:1.注册中心:作用主要是服务的注册发现和服务下线,在没有注册中心之前,两个服务的相互调用一般是通过http请求,然后把需要调用的服务名写到配置文件里,在微服务里这样做不但不够优雅,而且每个微服务都是个集群,每上一个集群服务都得该配置文件,非常繁琐,如果其中一台网络不通了也不好处理。而有了注册中心之后,所以服务都向注册中心注册,每个服务再把注册中心的服务缓存到本地,通过http请求或rpc调用。注册中心再通过心跳机制检查各注册服务的健康性,把不健康的服务及时同步到

2020-11-05 15:51:56 231

原创 为什么使用微服务

1.单机服务单机特点:在一台linux机器上部署一个tomcat服务,然后由浏览器发起http请求,tomcat将请求转发到项目由springmvc处理,经过controller->service->mapper->mysql.返回数据。优点:维护简单,就一台服务器。缺点:可处理的请求量有限单机服务在公司刚成立时还是可以用的,当公司用户量慢慢增多,发现mysql服务器cpu,内存都还撑得住,但web服务器不行了,cpu和内存使用率陡增,甚至在高峰期出现宕机的情况。此时我们想到的是增

2020-11-04 17:07:58 295

原创 使用jstack找cpu消耗大的线程

1.ps -ef | grep java 找到java进程id进程id:50362.top -Hp 5036找到进程id 5036中占cpu最高的线程:50743.printf ‘%x’ 5074 把5074转成二进制:13d24.jstack 5036 | grep 13d2 找到线程堆栈

2020-10-29 17:08:38 171

原创 hashmap

1.为什么用(h = key.hashCode()) ^ (h >>> 16)算hash?这要从数组下标位置的确定来考虑:tab[i = (n - 1) & hash],数组下标的确定是数组长度-1然后&元素的hash值。1.1(n - 1) & hash为什么能保证数组下标不能越界呢?这就跟hashMap容量有关,hashMap巧妙的利用了2的幂方来作为容量,默认情况下初始容量为16,之后扩容是旧容量的2倍。我们以16为例:16-1 =15,写成二进制:11

2020-09-02 11:03:04 172

原创 queue体系

阻塞queue:LinkedBlockingQueue:使用单链表储存元素,默认情况下无界,但也可以规定队列大小,底层主要通过reentrantLock和atomicInteger来保证线程安全,用condition的await 和signal实现阻塞。这里put和take使用了不同的锁,这样在高并发情况下会有更好的性能,这里需要注意一下的是await和signal都需要在上锁的情况下执行,因为await方法主要做了两个事情:一个是用单链表储存需要await的线程,线程设置成park状态。另一个是释放所有

2020-09-01 10:29:09 208

原创 list体系

arrayList新增:删除:主要是通过equal方法找到对应对象在数组中index,然后通过arraycopy方法跳过需要删除的元素,再把数组最后一个元素设置成null。Vector1.在ArrayList的基础上用synchronized保证了方法的线程安全。2.增加了自定义扩容因子,可以根据自己喜好扩容,默认是原容量的2倍3.默认构造器就会初始化容量为10,而ArrayList是在add时初始化。Stack继承于vector,在vector的基础上实现了先进后出方法,push方法用

2020-08-25 20:42:20 218

原创 volatile底层原理图解

cpu层面上可见性和指令重排的由来Java可见性和指令重排的由来

2020-08-21 11:22:48 254

原创 synchronized底层原理

1.synchronized实现原理synchronized借助对象的monitor来实现,每个对象都有monitor,monitor有_owner,_count,_entryList,_waitSet等属性,当一个线程访问synchronized修饰的代码块或方法时,首先会检查_owner是否指向线程,如果指向线程则判断是否是一个线程,是则获取锁,_count+1,不是则进入_entryList等待持有线程释放锁,_waitSet是在持有锁的线程调用了wait方法时进入等待的集合。2.编译器是如何知

2020-08-20 12:03:06 471

原创 CountDownLatch的工作流程

CountDownLatch的工作流程:1.通过CountDownLatch(int count)构造器给sync同步器的state赋值。2.每调countDown一次state数值-1,直到state为0时唤醒等待队列中head后的第一个线程。3.没调await方法一次都会去判断state是不是为0,当为0时直接执行,不为0时排队等待,直到被park唤醒。问题一:为什么使用共享锁而不用独占锁?独占锁只有在释放资源时才会唤醒head节点的下一个node,如果使用独占锁调用await方法的线程只会

2020-08-15 17:26:55 172

原创 ReentrantLock的公平锁和非公平锁实现图解

公平锁的获取和释放:可以看到这个过程跟AQS独占锁的获取和释放是一样的,实现公平锁的关键是tryRelease方法的实现:公平锁实现关键:当有资源时也会判断当前有没有线程在等待,只要有线程在等待不管有没有资源都要排队等待,这就保证了线程完全是按先后顺序执行。可重入实现细节:同一个线程可以在没有资源情况下无限次获取锁,通过上图可以看到,在state不是0的情况下会判断当前线程是否是持锁线程,是的情况下会改变state的值并return true。此时要注意,同一个线程lock几次,也要unloc

2020-08-15 15:47:53 698

原创 AQS图解

1.独占锁1.1独占锁的获取和释放1.2 addWaiter方法:1.3 acquireQueued方法注意:线程挂起之后就不自旋了,等待有线程调用unpark之后才会继续执行。1.4 release方法注意:这里调用unpark之后被唤醒的线程继续自旋开始竞争锁,如果还是没有竞争到会再次进入park睡眠状态。2.共享锁2.1共享锁的获取和释放1.如何进行唤醒线程?唤醒线程都是在解锁时唤醒,当竞争锁的线程没有获取到资源时,都会进行park,当有线程调用了unlock方法之后,

2020-08-14 16:55:18 391

原创 内存分析

《1》 https://www.cnblogs.com/ityouknow/p/5714703.html《1》数据分析命令 jmap -histo:live 13 | more《2》整体分析命令 jmap -heap 13https://blog.csdn.net/wcy708708/article/details/80541982https://www.ytexpress.cn/love/412102.htmlhttps://www.cnblogs.com/redcreen/archive/

2020-05-28 19:38:11 147

原创 记录一次jvm调优过程

1.查看gc情况:结果:服务启动时长是1天,进行了3240左右次minorGC,一共使用时间80s左右。也就是一次minirGC时间是0.02s,FGC是一次,时间是2.2s,fullGC时间过长,需要优化。1.为什么需要优化:FGC会不会导致请求失败?1.1查看GC方式是什么:新生代使用的是PS Young Generation回收器,也就是Parallel Scavenge回收器,特点是使用复制算法的多线程serial回收器,跟perNew区别是更注重程序的吞吐量,吞吐量是要尽量保证系

2020-05-26 16:56:06 1852 9

原创 记录一次sharingjdbc引起的fullgc频繁问题,总结一下fullgc频繁解决的方案

背景:最近做了个需求,为了优化效率所以做了本地缓存和redis缓存,这个跟实际问题没有很大关系,但在排查问题时造成了一定的干扰,导致排查时间变长了,这个问题的现象是上线后cpu急剧增高,fullgc次数比younggc次数多,而且每次fullgc回收的内存很少,fullgc频繁。1.问题现象图:2.分析:通过gc的情况可以看出一直在进行fullgc而没有进行younggc,这种情况猜测是有大对象执行进入了老年代,而且在老年代回收时没有被回收掉,正好代码里也使用的本地缓存,在上之前是有计算本地缓存会占

2020-05-26 16:26:57 716 1

原创 使用java将几张图片合成一张图片

背景描述:最近在做app推送消息,在做管住人推送需要把有更新的关注人头像合成一张图片,展示示例如下:花了一些时间来弄这个,之前没做过图片处理,所以记录一下,合成之后的样例如下:下面是代码:/** * * @Title: modifyImagetogeter * @Description: 将几张图片合成一张图片 * @param: @param b1 *...

2020-04-23 10:54:38 2905

原创 一次缓存雪崩的思考

场景:我们为了提高接口的响应时间,在一些高并发的场景(例如我们app的首页,分享页),都会做redis缓存,redis缓存大多数情况下我们都会设置有效时间,此时就可能出现缓存雪崩的情况,也就是在高并发时缓存失效,同一时间都去访问mysql,当然访问mysql是在设置了懒加载的情况(就是缓存没有取到,就去数据库取),此时就可能造成mysql巨大的压力,我们采用的方法一般是这几个。1.不采用懒加载,...

2020-04-14 11:53:43 154

原创 记录一次java集成华为,oppo,vivo推送的经历

背景:最近公司app做用户推送功能,通过用户分析,85%的用户用的是华为,oppo,vivo。所以先考虑集成此三个平台,再开发过程中还是有一些坑的,在此记录一下。1.华为推送:sdk地址:https://developer.huawei.com/consumer/cn/service/hms/catalog/huaweipush_v3.html?page=hmssdk_huaweipush_s...

2020-04-11 16:19:12 1678

原创 使用Pair优雅的实现键值匹对

场景:很多accessToken是有有效期的,在有效期后需要重新请求accessToken,此时我们需要把accessToken和有效时间关联起来,当然此时使用redis是最佳选择,但如果我们想放在java本地呢?java中常见键值对是map,但此时已经不适合了,因为accessToken和有效期都是变动的,而pair特别适合此场景。/* * Copyright (c) 2010, 2013,...

2020-04-03 17:37:19 534

原创 mybatis使用generator生成器生成entity,mapper,xml模版类及自己写sql情况处理

在使用mybatis时总是要生成实体类,mapper以及常用的mapper.xml文件,手写既没有技术含量还浪费时间,所以使用generator生成器会很方便。pom.xml配置:<dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-ge...

2020-03-19 12:10:13 840

原创 用mybatis实现批量插入在使用sharingJdbc分库分表情况下遇到的问题

service层代码:@Override public void testBatchInsert() { List<VideoAuditProcess> datas = new ArrayList<>(); for (int i = 1; i < 5; i++) { Long videoId = Long.parseLong(i + ""); ...

2020-03-18 21:43:26 3243 1

原创 使用@ExceptionHandler实现全局抛异常,完成优雅的报错提示和程序处理

在处理程序过程中,我们总是会需要处理一些异常,有时需要在报错的同时给前端和客户提示,此时一种通常的做法是在service抛异常,然后在controller层try-catch住给以错误信息和错误码的提示。这样会显得比较乱,controller层到处是try-catch。此时使用@ExceptionHandler能够统一处理提示异常,处理方式更加优雅。1.全局处理类:@ControllerAdv...

2020-03-13 21:06:35 1659

原创 工作问题总结

1.场景描述:在本地和测试环境能正常打印日志,在预发布环境不能打印日志问题解决:org.slf4j.LoggerFactory包读的是log4j2.xml文件,org.apache.log4j.Logger读的是log4j.Properties文件,而且在不配置log4j.Properties文件的情况下在本地是能打印出日志的,在预发布不能打印的原因未知,但改成org.slf4j.LoggerF...

2019-12-12 22:51:11 157

原创 tomcat性能调优

1.连接优化,把阻塞变成非阻塞:tomcat的连接方式:org.apache.coyote.http11.Http11Protocol 阻塞模式的连接协议org.apache.coyote.http11.Http11NioProtocol 非阻塞模式的连接协议,jdk1.4开始支持org.apache.coyote.http11.Http11AprProtocol – 本地连接协议,jdk...

2019-11-12 17:19:20 178

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除