RabbitMQ
1. 基本架构 publisher:生产者 consumer:消费者 exchange 个:交换机,负责消息路由 queue:队列,存储消息 virtualHost:虚拟主机,隔离不同租户的 exchange、queue、消息的隔离 2. 消息模型 WorkQueue: 让多个消费者绑定到一个队列,共同消费队列中的消息。 Topic: 在绑定队列和交换机的时候指定路由键 1234@Bean public Binding bindingTopicQueue1(Queue topicQueue1, TopicExchange topicExchange){ return...
个人Spring问题总结
1. 循环依赖先看看 Bean 生命周期 A 依赖 B,B 依赖 A,就成了循环依赖。 12345678910111213@Service public class CircularServiceA { @Autowired private CircularServiceB circularServiceB; } @Service public class CircularServiceB { @Autowired private CircularServiceA circularServiceA; } 看看 Spring 的三级缓存只有 A 时,创建流程为引入 B,变为B populatedBean 查找依赖项 A 的时候,从一级缓存中虽然未获取到 A,但是发现 A 在创建中。此时,从三级缓存中获取 A 的 singletonFactory 调用工厂方法(singletonObject = singletonFactory.getObject();),创建 getEarlyBeanReference A 的早期引用并返回。B 引用到 A...
Mybatis部分面试题总结
1. 怎么进行一对一或一对多映射?首先准备 2 张表、4 个实体类 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950@Data @Builder @AllArgsConstructor @NoArgsConstructor public class GroupDO { private Integer id; private String groupName; } @Data @Builder @AllArgsConstructor @NoArgsConstructor public class UserDO { private Integer id; private String username; private String password; private Integer groupId; private Sex...
线程池原理
什么是线程池说白了就是一个线程集合 workerSet 和一个阻塞队列 workQueue。当用户向线程池提交一个任务(也就是线程)时,线程池会先将任务放入 workQueue 中。workerSet 中的线程会不断的从 workQueue 中获取线程然后执行。当 workQueue 中没有任务的时候,worker 就会阻塞,直到队列中有任务了就取出来继续执行。 创建线程池1. 通过 Executor 框架的工具类 Executors 来创建。有很多内置的线程池,包括: FixedThreadPool:固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。 SingleThreadExecutor: 只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。 CachedThreadPool:...
ConcurrentHashMap部分源码
1. ConcurrentHashMap 1.7Java 7 中 ConcurrentHashMap 的存储结构如上图,ConcurrnetHashMap 由很多个 Segment 组合,而每一个 Segment 是一个类似于 HashMap 的结构,所以每一个 HashMap 的内部可以进行扩容。但是 Segment 的个数一旦初始化就不能改变,默认 Segment 的个数是 16 个,你也可以认为 ConcurrentHashMap 默认支持最多 16 个线程并发,每次加锁都只会对 Segment 进行加锁,也就是分段锁 2. ConcurrentHashMap 1.8 数据结构改进:与 HashMap 一样,将原先 数组+单链表 的数据结构,变更为 数组+单链表+红黑树 的结构。当出现哈希冲突时,数据会存入数组指定桶的单链表,当链表长度达到 8,则将其转换为红黑树结构,这样其查询的时间复杂度可以降低到 $$O(logN)$$,以改进性能。 并发机制改进: 取消 segments 字段,直接采用 transient volatile...
HashMap部分源码
HashMap构造方法12345678910111213141516171819202122232425262728// 默认构造函数。 public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted } // 包含另一个“Map”的构造函数 public HashMap(Map<? extends K, ? extends V> m) { this.loadFactor = DEFAULT_LOAD_FACTOR; putMapEntries(m, false);//下面会分析到这个方法 } // 指定“容量大小”的构造函数 public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } // 指定“容量大小”和“负载因子”的构造函数 public HashMap(int...
ThreadLocal源码
数据结构ThreadLocalMap 是 ThreadLocal 的静态内部类,它内部维护了一个 Entry 数组,key 是 ThreadLocal 对象,value 是线程的局部变量本身。 123456789static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } 可以看到,这里的 Entry 继承了 WeakReference,它限定了 key 是一个弱引用,弱引用的好处是当内存不足时,JVM 会回收 ThreadLocal 对象,并且将其对应的 Entry 的 value 设置为 null,这样在很大程度上可以避免内存泄漏。 弱引用需要用...
AQS原理
借助 ReentrantLock 来解释。 1. AQS概念AQS是JUC提供的一个用于构建锁和同步容器的基础类。JUC包内的许多类都是基于AQS构建,例如ReentrantLock、 Semaphore、CountDownLatch、ReentrantReadWriteLock、FutureTask等。AQS解决了在实现同步容器时设计的大 量细节问题。 AQS是CLH队列的一个变种,主要原理和CLH队列差不多,这也是前面对CLH队列进行长篇大论介绍的原因。AQS队列 内部维护的是一个FIFO的双向链表,这种结构的特点是每个数据结构都有两个指针,分别指向直接的前驱节点和直接 的后驱节点。所以双向链表可以从任意一个节点开始很方便地访问前驱节点和后驱节点。每个节点其实是由线程封装 的,当线程争抢锁失败后会封装成Node加入到AQS队列中去;当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞 的节点(线程)。 1.1 ...
synchronized原理
64 位虚拟机 Mark Word(java 对象头) 从上到下依次是普通状态、偏向锁、轻量级锁、重量级锁 Monitor 被翻译为监视器或管程每个对象实例都会有一个 Monitor,Monitor 可以和对象一起创建、销毁。Monitor 是由 ObjectMonitor 实现,而 ObjectMonitor 是由 C++ 的 ObjectMonitor.hpp 文件实现。 当多个线程同时访问一段同步代码时,多个线程会先被存放在 EntryList 集合中,处于 block 状态的线程,都会被加入到该列表。接下来当线程获取到对象的 Monitor 时,Monitor 是依靠底层操作系统的 Mutex Lock 来实现互斥的,线程申请 Mutex 成功,则持有该 Mutex,其它线程将无法获取到该 Mutex。 如果线程调用 wait() 方法,就会释放当前持有的 Mutex,并且该线程会进入 WaitSet 集合中,等待下一次被唤醒。如果当前线程顺利执行完方法,也将释放 Mutex。每个 Java 对象都可以关联一个 Monitor 对象,如果使用 synchronized...
云间清醒梦
...









