diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE new file mode 100644 index 0000000..f556da0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE @@ -0,0 +1,13 @@ +**在提交issue之前请回答以下问题,谢谢!** + +> 建议首先查看是否已经有类似的 Issues (提交时可删除该提示) + +### 你使用的是哪个版本 + +### 预期结果 + +### 实际结果 + +### 重现结果的步骤 + +### 其他相关信息 \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE new file mode 100644 index 0000000..28a3805 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE @@ -0,0 +1,16 @@ +如果是文字类 PR,请按照 [中文排版指北](https://github.com/sparanoid/chinese-copywriting-guidelines) 进行编写(提交时可删除该提示)。 + +**What kind of change does this PR introduce?** (check at least one) + +- [ ] Bugfix +- [ ] Feature +- [ ] Code style update +- [ ] Refactor +- [ ] Build-related changes +- [ ] Other, please describe: + + +**The description of the PR:** + + +**Other information:** \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9396aad --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: java + +install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true +script: mvn -DskipTests=true clean install + + +branches: + only: + - master \ No newline at end of file diff --git a/MD/HashMap.md b/MD/HashMap.md index 2f1b86b..7146e6b 100644 --- a/MD/HashMap.md +++ b/MD/HashMap.md @@ -4,7 +4,7 @@ ![](https://ws2.sinaimg.cn/large/006tNc79gy1fn84b0ftj4j30eb0560sv.jpg) -如图所示,HashMap 底层是基于数据和链表实现的。其中有两个重要的参数: +如图所示,HashMap 底层是基于数组和链表实现的。其中有两个重要的参数: - 容量 - 负载因子 @@ -22,6 +22,37 @@ get 和 put 类似,也是将传入的 Key 计算出 index ,如果该位置上是一个链表就需要遍历整个链表,通过 `key.equals(k)` 来找到对应的元素。 +## 遍历方式 + + +```java + Iterator> entryIterator = map.entrySet().iterator(); + while (entryIterator.hasNext()) { + Map.Entry next = entryIterator.next(); + System.out.println("key=" + next.getKey() + " value=" + next.getValue()); + } +``` + +```java +Iterator iterator = map.keySet().iterator(); + while (iterator.hasNext()){ + String key = iterator.next(); + System.out.println("key=" + key + " value=" + map.get(key)); + + } +``` + +```java +map.forEach((key,value)->{ + System.out.println("key=" + key + " value=" + value); +}); +``` + +**强烈建议**使用第一种 EntrySet 进行遍历。 + +第一种可以把 key value 同时取出,第二种还得需要通过 key 取一次 value,效率较低, 第三种需要 `JDK1.8` 以上,通过外层遍历 table,内层遍历链表或红黑树。 + + ## notice 在并发环境下使用 `HashMap` 容易出现死循环。 @@ -41,4 +72,4 @@ get 和 put 类似,也是将传入的 Key 计算出 index ,如果该位置 大大提高了查询效率。 -多线程场景下推荐使用 [ConcurrentHashMap](https://github.com/crossoverJie/Java-Interview/blob/master/MD/ConcurrentHashMap.md)。 \ No newline at end of file +多线程场景下推荐使用 [ConcurrentHashMap](https://github.com/crossoverJie/Java-Interview/blob/master/MD/ConcurrentHashMap.md)。 diff --git a/MD/Limiting.md b/MD/Limiting.md index e97f23d..2b76019 100644 --- a/MD/Limiting.md +++ b/MD/Limiting.md @@ -54,4 +54,5 @@ ``` -> [更多信息](https://crossoverjie.top/2017/08/11/sbc4/) +1. [单 JVM 限流](http://crossoverjie.top/2017/08/11/sbc4/) +2. [分布式限流](http://crossoverjie.top/2018/04/28/sbc/sbc7-Distributed-Limit/) diff --git a/MD/LinkedList.md b/MD/LinkedList.md index e42384d..1e0a4f6 100644 --- a/MD/LinkedList.md +++ b/MD/LinkedList.md @@ -1,8 +1,8 @@ # LinkedList 底层分析 -![](https://ws1.sinaimg.cn/large/006tKfTcgy1fmtdndjiwej30hj06mabj.jpg) +![](https://ws4.sinaimg.cn/large/006tKfTcly1fqzb66c00gj30p7056q38.jpg) -如图所示 `LinkedList` 底层是基于双向链表实现的,也是实现了 `List` 接口,所以也拥有 List 的一些特点。 +如图所示 `LinkedList` 底层是基于双向链表实现的,也是实现了 `List` 接口,所以也拥有 List 的一些特点(JDK1.7/8 之后取消了循环,修改为双向链表)。 ## 新增方法 @@ -56,9 +56,12 @@ 由此可以看出是使用二分查找来看 `index` 离 size 中间距离来判断是从头结点正序查还是从尾节点倒序查。 -这样的效率是非常低的,特别是当 index 距离 size 的中间位置越远时。 +- `node()`会以`O(n/2)`的性能去获取一个结点 + - 如果索引值大于链表大小的一半,那么将从尾结点开始遍历 + +这样的效率是非常低的,特别是当 index 越接近 size 的中间值时。 总结: - LinkedList 插入,删除都是移动指针效率很高。 -- 查找需要进行遍历查询,效率较低。 \ No newline at end of file +- 查找需要进行遍历查询,效率较低。 diff --git a/MD/MemoryAllocation.md b/MD/MemoryAllocation.md index dfd8f0c..ff9080e 100644 --- a/MD/MemoryAllocation.md +++ b/MD/MemoryAllocation.md @@ -28,7 +28,7 @@ ## 方法区 方法区主要用于存放已经被虚拟机加载的类信息,如`常量,静态变量`。 -这块区域也被称为`老年代`。 +这块区域也被称为`永久代`。 ### 运行时常量池 diff --git a/MD/TCP:IP.md b/MD/TCP-IP.md similarity index 100% rename from MD/TCP:IP.md rename to MD/TCP-IP.md diff --git a/MD/Thread-common-problem.md b/MD/Thread-common-problem.md index a8a0734..1669307 100644 --- a/MD/Thread-common-problem.md +++ b/MD/Thread-common-problem.md @@ -4,7 +4,7 @@ 多线程并不一定是要在多核处理器才支持的,就算是单核也是可以支持多线程的。 CPU 通过给每个线程分配一定的时间片,由于时间非常短通常是几十毫秒,所以 CPU 可以不停的切换线程执行任务从而达到了多线程的效果。 -但是由于在线程切换的时候需要保存本次执行的信息([详见](https://github.com/crossoverJie/Java-Interview/blob/master/MemoryAllocation.md#%E7%A8%8B%E5%BA%8F%E8%AE%A1%E6%95%B0%E5%99%A8)),在该线程被 CPU 剥夺时间片后又再次运行恢复上次所保存的信息的过程就成为上下文切换。 +但是由于在线程切换的时候需要保存本次执行的信息([详见](https://github.com/crossoverJie/Java-Interview/blob/master/MD/MemoryAllocation.md#%E7%A8%8B%E5%BA%8F%E8%AE%A1%E6%95%B0%E5%99%A8)),在该线程被 CPU 剥夺时间片后又再次运行恢复上次所保存的信息的过程就成为上下文切换。 > 上下文切换是非常耗效率的。 diff --git a/MD/collection/HashSet.md b/MD/collection/HashSet.md index 5df569d..a18212d 100644 --- a/MD/collection/HashSet.md +++ b/MD/collection/HashSet.md @@ -1,4 +1,4 @@ -# HashSet 底层分析 +# HashSet `HashSet` 是一个不允许存储重复元素的集合,它的实现比较简单,只要理解了 `HashMap`,`HashSet` 就水到渠成了。 @@ -19,7 +19,7 @@ ## 构造函数 -``` +```java public HashSet() { map = new HashMap<>(); } diff --git a/MD/newObject.md b/MD/newObject.md index 50c80d3..6c091b4 100644 --- a/MD/newObject.md +++ b/MD/newObject.md @@ -46,7 +46,7 @@ ### Eden 区分配 简单的来说对象都是在堆内存中分配的,往细一点看则是优先在 `Eden` 区分配。 -这里就涉及到堆内存的划分了,为了方便垃圾回收,JVM 将对内存分为新生代和老年代。 +这里就涉及到堆内存的划分了,为了方便垃圾回收,JVM 将堆内存分为新生代和老年代。 而新生代中又会划分为 `Eden` 区,`from Survivor、to Survivor` 区。 diff --git a/README.md b/README.md index abb0594..bc2b5bb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +[![Build Status](https://travis-ci.org/crossoverJie/Java-Interview.svg?branch=master)](https://travis-ci.org/crossoverJie/Java-Interview) +[![QQ群](https://img.shields.io/badge/QQ%E7%BE%A4-787381170-yellowgreen.svg)](https://jq.qq.com/?_wv=1027&k=5HPYvQk) + +[qq0groupsvg]: https://img.shields.io/badge/QQ%E7%BE%A4-787381170-yellowgreen.svg +[qq0group]: https://jq.qq.com/?_wv=1027&k=5HPYvQk + Java 知识点,继续完善中。 > 多数是一些 Java 基础知识、底层原理、算法详解。也有上层应用设计,其中不乏一些大厂面试真题。 @@ -5,11 +11,18 @@ Java 知识点,继续完善中。 如果对你有帮助请点下 `Star`,有疑问欢迎提 [Issues](https://github.com/crossoverJie/Java-Interview/issues),有好的想法请提 [PR](https://github.com/crossoverJie/Java-Interview/pulls)。 -### Java 集合 -- [ArrayList/Vector 底层分析](https://github.com/crossoverJie/Java-Interview/blob/master/MD/ArrayList.md) -- [LinkedList 底层分析](https://github.com/crossoverJie/Java-Interview/blob/master/MD/LinkedList.md) -- [HashMap 底层分析](https://github.com/crossoverJie/Java-Interview/blob/master/MD/HashMap.md) -- [LinkedHashMap 底层分析](https://github.com/crossoverJie/Java-Interview/blob/master/MD/collection/LinkedHashMap.md) + +[常用集合](https://github.com/crossoverJie/Java-Interview/blob/master/README.md#%E5%B8%B8%E7%94%A8%E9%9B%86%E5%90%88) | [Java 多线程](https://github.com/crossoverJie/Java-Interview/blob/master/README.md#java-%E5%A4%9A%E7%BA%BF%E7%A8%8B) | [JVM](https://github.com/crossoverJie/Java-Interview/blob/master/README.md#jvm) | [分布式相关](https://github.com/crossoverJie/Java-Interview/blob/master/README.md#%E5%88%86%E5%B8%83%E5%BC%8F%E7%9B%B8%E5%85%B3) |[常用框架\第三方组件](https://github.com/crossoverJie/Java-Interview/blob/master/README.md#%E5%B8%B8%E7%94%A8%E6%A1%86%E6%9E%B6%E7%AC%AC%E4%B8%89%E6%96%B9%E7%BB%84%E4%BB%B6)|[架构设计](https://github.com/crossoverJie/Java-Interview/blob/master/README.md#%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1)|[DB 相关](https://github.com/crossoverJie/Java-Interview/blob/master/README.md#db-%E7%9B%B8%E5%85%B3)|[数据结构与算法](https://github.com/crossoverJie/Java-Interview/blob/master/README.md#%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95)|[Netty 相关](https://github.com/crossoverJie/Java-Interview#netty-%E7%9B%B8%E5%85%B3)|[附加技能](https://github.com/crossoverJie/Java-Interview/blob/master/README.md#%E9%99%84%E5%8A%A0%E6%8A%80%E8%83%BD)|[联系作者](https://github.com/crossoverJie/Java-Interview#%E8%81%94%E7%B3%BB%E4%BD%9C%E8%80%85) +---- | --- | --- | ---| ---| ---| ---| ---| ---|---|--- + + + +### 常用集合 +- [ArrayList/Vector](https://github.com/crossoverJie/Java-Interview/blob/master/MD/ArrayList.md) +- [LinkedList](https://github.com/crossoverJie/Java-Interview/blob/master/MD/LinkedList.md) +- [HashMap](https://github.com/crossoverJie/Java-Interview/blob/master/MD/HashMap.md) +- [HashSet](https://github.com/crossoverJie/Java-Interview/blob/master/MD/collection/HashSet.md) +- [LinkedHashMap](https://github.com/crossoverJie/Java-Interview/blob/master/MD/collection/LinkedHashMap.md) ### Java 多线程 - [多线程中的常见问题](https://github.com/crossoverJie/Java-Interview/blob/master/MD/Thread-common-problem.md) @@ -22,7 +35,7 @@ Java 知识点,继续完善中。 - [深入理解线程通信](https://github.com/crossoverJie/Java-Interview/blob/master/MD/concurrent/thread-communication.md) - [交替打印奇偶数](https://github.com/crossoverJie/Java-Interview/blob/master/src/main/java/com/crossoverjie/actual/TwoThread.java) -### JMM(Java 内存模型) +### JVM - [Java 运行时内存划分](https://github.com/crossoverJie/Java-Interview/blob/master/MD/MemoryAllocation.md) - [类加载机制](https://github.com/crossoverJie/Java-Interview/blob/master/MD/ClassLoad.md) - [OOM 分析](https://github.com/crossoverJie/Java-Interview/blob/master/MD/OOM-analysis.md) @@ -32,23 +45,23 @@ Java 知识点,继续完善中。 ### 分布式相关 -- [基于 Redis 的分布式锁](https://github.com/crossoverJie/distributed-lock-redis) +- [分布式限流](http://crossoverjie.top/2018/04/28/sbc/sbc7-Distributed-Limit/) +- [基于 Redis 的分布式锁](http://crossoverjie.top/2018/03/29/distributed-lock/distributed-lock-redis/) +- [分布式缓存设计](https://github.com/crossoverJie/Java-Interview/blob/master/MD/Cache-design.md) +- [分布式 ID 生成器](https://github.com/crossoverJie/Java-Interview/blob/master/MD/ID-generator.md) -### 常用框架 +### 常用框架\第三方组件 - [Spring Bean 生命周期](https://github.com/crossoverJie/Java-Interview/blob/master/MD/spring/spring-bean-lifecycle.md) - [Spring AOP 的实现原理](https://github.com/crossoverJie/Java-Interview/blob/master/MD/SpringAOP.md) - -### SpringBoot +- [Guava 源码分析(Cache 原理)](https://crossoverjie.top/2018/06/13/guava/guava-cache/) - SpringBoot 启动过程 - -### Tomcat - Tomcat 类加载机制 + ### 架构设计 - [秒杀系统设计](https://github.com/crossoverJie/Java-Interview/blob/master/MD/Spike.md) -- [分布式缓存设计](https://github.com/crossoverJie/Java-Interview/blob/master/MD/Cache-design.md) -- [分布式 ID 生成器](https://github.com/crossoverJie/Java-Interview/blob/master/MD/ID-generator.md) +- [秒杀架构实践](http://crossoverjie.top/2018/05/07/ssm/SSM18-seconds-kill/) ### DB 相关 @@ -62,19 +75,25 @@ Java 知识点,继续完善中。 - [是否为快乐数字](https://github.com/crossoverJie/Java-Interview/blob/master/src/main/java/com/crossoverjie/algorithm/HappyNum.java#L38-L55) - [链表是否有环](https://github.com/crossoverJie/Java-Interview/blob/master/src/main/java/com/crossoverjie/algorithm/LinkLoop.java#L32-L59) - [从一个数组中返回两个值相加等于目标值的下标](https://github.com/crossoverJie/Java-Interview/blob/master/src/main/java/com/crossoverjie/algorithm/TwoSum.java#L38-L59) -- [一致 Hash 算法](https://github.com/crossoverJie/Java-Interview/blob/master/MD/Consistent-Hash.md) +- [一致性 Hash 算法](https://github.com/crossoverJie/Java-Interview/blob/master/MD/Consistent-Hash.md) - [限流算法](https://github.com/crossoverJie/Java-Interview/blob/master/MD/Limiting.md) - [三种方式反向打印单向链表](https://github.com/crossoverJie/Java-Interview/blob/master/src/main/java/com/crossoverjie/algorithm/ReverseNode.java) - [合并两个排好序的链表](https://github.com/crossoverJie/Java-Interview/blob/master/src/main/java/com/crossoverjie/algorithm/MergeTwoSortedLists.java) - [两个栈实现队列](https://github.com/crossoverJie/Java-Interview/blob/master/src/main/java/com/crossoverjie/algorithm/TwoStackQueue.java) +- [动手实现一个 LRU cache](http://crossoverjie.top/2018/04/07/algorithm/LRU-cache/) + +### Netty 相关 +- [SpringBoot 整合长连接心跳机制](https://crossoverjie.top/2018/05/24/netty/Netty(1)TCP-Heartbeat/) +- [从线程模型的角度看 Netty 为什么是高性能的?](https://crossoverjie.top/2018/07/04/netty/Netty(2)Thread-model/) ### 附加技能 -- [TCP/IP 协议](https://github.com/crossoverJie/Java-Interview/blob/master/MD/TCP%3AIP.md) +- [TCP/IP 协议](https://github.com/crossoverJie/Java-Interview/blob/master/MD/TCP-IP.md) +- [一个学渣的阿里之路](https://crossoverjie.top/2018/06/21/personal/Interview-experience/) ### 联系作者 > crossoverJie#gmail.com -![](https://ws4.sinaimg.cn/large/006tKfTcly1fochm4as0sj30by0bydgh.jpg) +![](https://ws2.sinaimg.cn/large/006tKfTcly1fsa01u7ro1j30gs0howfq.jpg) \ No newline at end of file diff --git a/src/main/java/com/crossoverjie/actual/LRUMap.java b/src/main/java/com/crossoverjie/actual/LRUMap.java index 906660c..c0a4596 100644 --- a/src/main/java/com/crossoverjie/actual/LRUMap.java +++ b/src/main/java/com/crossoverjie/actual/LRUMap.java @@ -131,14 +131,10 @@ private void addNode(K key, V value) { if (cacheSize == nodeCount) { //删除尾结点 delTail(); - - //写入头结点 - addHead(node); - } else { - addHead(node); - } + //写入头结点 + addHead(node); } diff --git a/src/main/java/com/crossoverjie/basic/HashMapTest.java b/src/main/java/com/crossoverjie/basic/HashMapTest.java new file mode 100644 index 0000000..011910b --- /dev/null +++ b/src/main/java/com/crossoverjie/basic/HashMapTest.java @@ -0,0 +1,42 @@ +package com.crossoverjie.basic; + +import java.security.Key; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Function: + * + * @author crossoverJie + * Date: 05/05/2018 12:42 + * @since JDK 1.8 + */ +public class HashMapTest { + public static void main(String[] args) { + Map map = new HashMap<>(16); + map.put("1", 1); + map.put("2", 2); + map.put("3", 3); + map.put("4", 4); + + Iterator> entryIterator = map.entrySet().iterator(); + while (entryIterator.hasNext()) { + Map.Entry next = entryIterator.next(); + System.out.println("key=" + next.getKey() + " value=" + next.getValue()); + } + System.out.println("============="); + + Iterator iterator = map.keySet().iterator(); + while (iterator.hasNext()){ + String key = iterator.next(); + System.out.println("key=" + key + " value=" + map.get(key)); + + } + + System.out.println("============="); + map.forEach((key, value) -> { + System.out.println("key=" + key + " value=" + map.get(key)); + }); + } +} diff --git a/src/main/java/com/crossoverjie/guava/CacheLoaderTest.java b/src/main/java/com/crossoverjie/guava/CacheLoaderTest.java new file mode 100644 index 0000000..7f9a367 --- /dev/null +++ b/src/main/java/com/crossoverjie/guava/CacheLoaderTest.java @@ -0,0 +1,89 @@ +package com.crossoverjie.guava; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.Interner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Function: + * + * @author crossoverJie + * Date: 2018/6/12 15:33 + * @since JDK 1.8 + */ +public class CacheLoaderTest { + private final static Logger LOGGER = LoggerFactory.getLogger(CacheLoaderTest.class); + private LoadingCache loadingCache ; + private final static Integer KEY = 1000; + + + private final static LinkedBlockingQueue QUEUE = new LinkedBlockingQueue<>(1000); + + + private void init() throws InterruptedException { + loadingCache = CacheBuilder.newBuilder() + .expireAfterWrite(2, TimeUnit.SECONDS) + + .build(new CacheLoader() { + @Override + public AtomicLong load(Integer key) throws Exception { + return new AtomicLong(0); + } + }); + + + for (int i = 10; i < 15; i++) { + QUEUE.put(i); + } + } + + private void checkAlert(Integer integer) { + try { + + //loadingCache.put(integer,new AtomicLong(integer)); + + TimeUnit.SECONDS.sleep(5); + + + LOGGER.info("当前缓存值={},缓存大小={}", loadingCache.get(KEY),loadingCache.size()); + LOGGER.info("缓存的所有内容={}",loadingCache.asMap().toString()); + loadingCache.get(KEY).incrementAndGet(); + + } catch (ExecutionException e ) { + LOGGER.error("Exception", e); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + public static void main(String[] args) throws InterruptedException { + CacheLoaderTest cacheLoaderTest = new CacheLoaderTest() ; + cacheLoaderTest.init(); + + + + while (true) { + + try { + Integer integer = QUEUE.poll(200, TimeUnit.MILLISECONDS); + if (null == integer) { + break; + } + //TimeUnit.SECONDS.sleep(5); + cacheLoaderTest.checkAlert(integer); + LOGGER.info("job running times={}", integer); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + +} diff --git a/src/test/java/com/crossoverjie/actual/LRUMapTest.java b/src/test/java/com/crossoverjie/actual/LRUMapTest.java index 371eb3b..eb9dcc2 100644 --- a/src/test/java/com/crossoverjie/actual/LRUMapTest.java +++ b/src/test/java/com/crossoverjie/actual/LRUMapTest.java @@ -39,6 +39,37 @@ public void put2() throws Exception { System.out.println(lruMap.toString()); } + @Test + public void put3() throws Exception { + LRUMap lruMap = new LRUMap(4) ; + lruMap.put("1",1) ; + lruMap.put("2",2) ; + lruMap.put("3",3) ; + lruMap.put("2",2) ; + + System.out.println(lruMap.toString()); + + lruMap.put("4",4) ; + System.out.println(lruMap.toString()); + + lruMap.put("5",5) ; + System.out.println(lruMap.toString()); + } + + @Test + public void put4() throws Exception { + LRUMap lruMap = new LRUMap(3) ; + lruMap.put("1",1) ; + lruMap.put("2",2) ; + lruMap.put("3",3) ; + + System.out.println(lruMap.toString()); + lruMap.put("2",2) ; + + System.out.println(lruMap.toString()); + + } + @Test public void get() throws Exception { LRUMap lruMap = new LRUMap(3) ; @@ -56,7 +87,7 @@ public void get() throws Exception { } @Test - public void get3() throws Exception { + public void get2() throws Exception { LRUMap lruMap = new LRUMap(3) ; lruMap.put("1",1) ; lruMap.put("2",2) ; @@ -72,7 +103,7 @@ public void get3() throws Exception { } @Test - public void get4() throws Exception { + public void get3() throws Exception { LRUMap lruMap = new LRUMap(3) ; lruMap.put("1",1) ; lruMap.put("2",2) ;