├── .gitignore
├── README.md
├── catalog
├── java.md
├── redis.md
├── spring-cloud.md
├── spring.md
├── springboot.md
├── 架构之路.md
└── 面试篇.md
├── jdk
├── JVM相关
│ └── JDK7和JDK8的内存区域划分.md
├── NIO
│ ├── NIO
│ │ ├── NIO之 通道之间的数据传输.md
│ │ ├── NIO之Channel.md
│ │ ├── NIO之DatagramChannel.md
│ │ ├── NIO之FileChannel.md
│ │ ├── NIO之Pipe.md
│ │ ├── NIO之Scatter和Gather.md
│ │ ├── NIO之ServerSocketChannel.md
│ │ ├── NIO之SocketChannel.md
│ │ ├── NIO之buffer.md
│ │ └── NIO之selector.md
│ └── 三种IO的总结.md
├── collection
│ ├── ArrayList.md
│ ├── HashMap.md
│ ├── LinkedHashMap.md
│ ├── LinkedList.md
│ ├── Spliterator.md
│ └── Vector.md
├── jdk8
│ ├── Lambda.md
│ ├── Lambda在集合中的使用.md
│ ├── 使用Optional.md
│ ├── 并行流.md
│ ├── 日期类
│ │ ├── 操作解析格式化日期.md
│ │ └── 日期类.md
│ └── 流
│ │ ├── CompletableFuture.md
│ │ ├── 分区.md
│ │ ├── 分组.md
│ │ ├── 收集器.md
│ │ ├── 数值流.md
│ │ └── 流创建的几种方式.md
└── thread
│ ├── CAS.md
│ ├── CountDownLatch源码解析.md
│ ├── CyclicBarrier源码解析.md
│ ├── Exchanger.md
│ ├── ReentrantLock.md
│ ├── ReentrantLock源码分析.md
│ ├── Semaphore.md
│ ├── Thead源码分析 .md
│ ├── ThreadLocal源码分析.md
│ ├── happens-bofore.md
│ ├── java内存模型重排序.md
│ ├── java锁的升级.md
│ ├── unSafe.md
│ ├── volatile 的实现原理.md
│ ├── 多线程的创建方式.md
│ ├── 深入分析 CAS.md
│ ├── 深入分析 synchronized 的实现原理.md
│ ├── 深入理解ConcurrentSkipListMap.md
│ ├── 理解AbstractQueuedSynchronized.md
│ └── 读写锁-ReentrantReadWriteLock.md
├── linux
└── VMware如何配置静态IP.md
├── markdown
└── markdown--table样式.md
├── mysql
├── mysql--InnoDB.md
├── mysql--MyISAM.md
├── mysql--MySQL慢日志.md
├── mysql--explain.md
├── mysql--mysql cluster.md
├── mysql--未解决的问题.md
├── mysql--索引类型.md
├── mysql中涉及的技术.md
├── mysql中的搜索引擎.md
└── 悲观锁和乐观锁的实现.md
├── redis
├── Bitmpas.md
├── HyperLogLog.md
├── PipeLine.md
├── RDB和AOF.md
├── redis--Hash.md
├── redis--list.md
├── redis--string.md
├── redis--zset.md
├── redis--发布订阅.md
├── redis-benchmark详解.md
├── redis-cli详解.md
├── redis-server详解.md
├── redis-set.md
├── redis全局命令.md
├── 主从复制
│ ├── 主从复制中读写分离带来的问题.md
│ ├── 主从复制的原理.md
│ ├── 主从复制的拓扑结构.md
│ └── 如何配置主从.md
├── 事务和Lua.md
├── 哨兵
│ ├── redis哨兵配置说明.md
│ ├── sentinel命令.md
│ ├── 哨兵原理.md
│ └── 如何配置redis哨兵.md
├── 慢查询分析.md
├── 缓存设计
│ └── 缓存设计.md
├── 阻塞
│ └── 发现阻塞.md
└── 集群
│ └── redis cluster.md
├── spring-cloud
├── Feign
│ ├── Feign传递复杂对象.md
│ ├── Feign入门教程.md
│ ├── Feign功能.md
│ ├── Feign和Hystrix结合使用.md
│ ├── Feign实现负载均衡.md
│ └── Feign的介绍.md
├── Hystrix
│ ├── Actuator.md
│ ├── HystrixCommand和HystrixObservableCommand.md
│ ├── Hystrix入门小例子.md
│ ├── Hystrix合并请求.md
│ ├── Hystrix异常处理机制.md
│ ├── Hystrix概述.md
│ ├── Hystrix线程传递和并发策略.md
│ ├── Hystrix缓存处理.md
│ ├── Hystrix配置文件说明.md
│ └── Turbine聚合Hystrix.md
├── config
│ ├── config入门示例.md
│ ├── git配置详解.md
│ ├── 使用多个git库.md
│ └── 基于db的config.md
├── consul
│ ├── consul具体功能.md
│ ├── consul实现服务的注册和发现.md
│ ├── consul概念介绍.md
│ ├── consul的安装.md
│ └── consul的配置中心.md
├── eureka
│ ├── eureka rest api.md
│ ├── eureka入门教程.md
│ └── eureka配置项.md
├── gateway
│ ├── gateWay内置的Filter.md
│ ├── gateWay概念.md
│ ├── gatewayFileter和GlobalFilter.md
│ ├── gateway基于服务发现的路由规则.md
│ └── gateway路由断言.md
├── ribbon
│ ├── RestTemplate对象.md
│ ├── Ribbon入门教程.md
│ ├── Ribbon实践.md
│ └── 使用ribbon调用第三方HTTPS接口.md
├── swagger
│ ├── swagger和zuul的结合.md
│ └── swagger常用注解.md
├── zuul
│ ├── Zuul-Filter责任链.md
│ ├── Zuul入门教程.md
│ ├── Zuul功能.md
│ ├── Zuul动态路由.md
│ ├── Zuul权限.md
│ ├── Zuul灰度发布.md
│ ├── Zuul配置.md
│ └── Zuul限流.md
├── 备注.md
└── 链路监控
│ ├── Sleuth基本术语.md
│ ├── Sleuth基本用法.md
│ ├── skywalking介绍.md
│ └── zipkin的基本使用.md
├── spring
├── Spring注册解析的bean.md
├── Spring自定义标签解析.md
├── Spring默认标签中的自定义标签解析.md
├── Spring默认标签解析.md
├── spring核心类.md
├── 深度解析:spring是如何实现从配置文件到注入bean.md
└── 配置文件的封装.md
├── springboot
└── springboot如何实现email发送.md
├── web
├── HTTP和HTTPS.md
└── 对称加密.md
├── 数据结构
├── B+树.md
├── B树.md
├── 二叉搜索树.md
├── 排序
│ ├── 八种排序算法.md
│ └── 扩展:三种交换数字的方式.md
└── 红黑树.md
├── 架构之路
├── 代码质量管理平台SonarQube
│ └── 代码质量管理平台SonarQube.md
└── 技术相关
│ └── Redis--防击穿和雪崩.md
└── 面试题
├── Spring
├── SpringAOP.md
├── SpringBean循环创建.md
├── SpringIoc.md
├── Spring事务.md
└── 几种代理的实现方式.md
└── Zookeeper
├── Zookeeper命令.md
└── Zookeeper面试题.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | .gitignore
3 | .idea/
4 | git/
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # markdown
2 | >关于自己的一些学习文档和学习心得都放在这里啦!!!
3 |
4 | # mysql
5 | [mysql--InnoDB](https://github.com/wuxiaobo000111/markdown/blob/master/mysql/mysql--InnoDB.md "mysql--InnoDB")
6 |
7 | [mysql--MyISAM](https://github.com/wuxiaobo000111/markdown/blob/master/mysql/mysql--MyISAM.md "mysql--MyISAM")
8 |
9 | [mysql--索引类型](https://github.com/wuxiaobo000111/markdown/blob/master/mysql/mysql--%E7%B4%A2%E5%BC%95%E7%B1%BB%E5%9E%8B.md "mysql--索引类型")
10 |
11 | [mysql--搜索引擎](https://github.com/wuxiaobo000111/markdown/blob/master/mysql/mysql%E4%B8%AD%E7%9A%84%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E.md "mysql--搜索引擎")
12 |
13 | [悲观锁和乐观锁的实现](https://github.com/wuxiaobo000111/markdown/blob/master/mysql/%E6%82%B2%E8%A7%82%E9%94%81%E5%92%8C%E4%B9%90%E8%A7%82%E9%94%81%E7%9A%84%E5%AE%9E%E7%8E%B0.md "悲观锁和乐观锁的实现")
14 |
15 | [mysql--explain](https://github.com/wuxiaobo000111/markdown/blob/master/mysql/mysql--explain.md "悲观锁和乐观锁的实现")
16 |
17 | [MySQL Cluster](https://github.com/wuxiaobo000111/markdown/blob/master/mysql/mysql--mysql%20cluster.md "MySQL Cluster")
18 |
19 | [mysql--慢日志](https://github.com/wuxiaobo000111/markdown/blob/master/mysql/mysql--MySQL%E6%85%A2%E6%97%A5%E5%BF%97.md "慢日志")
20 |
21 | # java
22 | [java](https://github.com/wuxiaobo000111/markdown/blob/master/catalog/java.md "java")
23 |
24 |
25 |
26 | # linux
27 | [VMware如何配置静态IP](https://github.com/wuxiaobo000111/markdown/blob/master/linux/VMware%E5%A6%82%E4%BD%95%E9%85%8D%E7%BD%AE%E9%9D%99%E6%80%81IP.md "VMware如何配置静态IP")
28 |
29 | # 数据结构
30 |
31 |
32 | [八大排序算法](https://github.com/wuxiaobo000111/markdown/blob/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E6%8E%92%E5%BA%8F/%E5%85%AB%E7%A7%8D%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.md "八大排序算法")
33 |
34 | [三种交换数字的方式](https://github.com/wuxiaobo000111/markdown/blob/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E6%8E%92%E5%BA%8F/%E6%89%A9%E5%B1%95%EF%BC%9A%E4%B8%89%E7%A7%8D%E4%BA%A4%E6%8D%A2%E6%95%B0%E5%AD%97%E7%9A%84%E6%96%B9%E5%BC%8F.md "三种交换数字的方式")
35 |
36 |
37 | [B-树](https://github.com/wuxiaobo000111/markdown/blob/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/B%E6%A0%91.md "B-树")
38 |
39 | [B+树](https://github.com/wuxiaobo000111/markdown/blob/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/B%2B%E6%A0%91.md "B+树")
40 |
41 |
42 | [二叉搜索树](https://github.com/wuxiaobo000111/markdown/blob/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.md "二叉搜索树")
43 |
44 |
45 |
46 | # WEB
47 |
48 | [HTTP和HTTPS](https://github.com/wuxiaobo000111/markdown/blob/master/web/HTTP%E5%92%8CHTTPS.md "HTTP和HTTPS")
49 |
50 |
51 | [对称加密](https://github.com/wuxiaobo000111/markdown/blob/master/web/%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86.md "对称加密")
52 |
53 |
54 | # redis
55 |
56 |
57 | [redis相关](
58 | https://github.com/wuxiaobo000111/markdown/blob/master/catalog/redis.md "redis相关")
59 |
60 |
61 | # spring boot
62 |
63 | [spring boot技术相关](
64 | https://github.com/wuxiaobo000111/Java--apollo/blob/master/catalog/springboot.md "spring boot技术相关")
65 |
66 |
67 | # Spring-cloud
68 |
69 | [spring-cloud 组件](
70 | https://github.com/wuxiaobo000111/markdown/blob/master/catalog/spring-cloud.md "spring-cloud 组件")
71 |
72 |
73 |
74 | # 架构之路
75 |
76 | [架构之路](
77 | https://github.com/wuxiaobo000111/Java--apollo/blob/master/catalog/%E6%9E%B6%E6%9E%84%E4%B9%8B%E8%B7%AF.md "架构之路")
78 |
79 |
80 | # 面试篇
81 |
82 | [面试篇](
83 | https://github.com/wuxiaobo000111/Java--apollo/blob/master/catalog/%E9%9D%A2%E8%AF%95%E7%AF%87.md "面试篇")
--------------------------------------------------------------------------------
/catalog/redis.md:
--------------------------------------------------------------------------------
1 | # redis
2 |
3 | ## 基础
4 | [redis--hash](https://github.com/wuxiaobo000111/markdown/blob/master/redis/redis--Hash.md "redis--hash")
5 |
6 | [redis--list](https://github.com/wuxiaobo000111/markdown/blob/master/redis/redis--list.md "redis --list")
7 |
8 | [redis--string](https://github.com/wuxiaobo000111/markdown/blob/master/redis/redis--string.md
9 | "redis--string")
10 |
11 | [redis--zset](https://github.com/wuxiaobo000111/markdown/blob/master/redis/redis--zset.md "redis--zset")
12 |
13 | [redis--set](https://github.com/wuxiaobo000111/markdown/blob/master/redis/redis-set.md "redis--set")
14 |
15 | [redis--全局命令](https://github.com/wuxiaobo000111/markdown/blob/master/redis/redis%E5%85%A8%E5%B1%80%E5%91%BD%E4%BB%A4.md "redis--全局命令")
16 |
17 | [redis--Bitmaps](https://github.com/wuxiaobo000111/markdown/blob/master/redis/Bitmpas.md "redis--Bitmaps")
18 |
19 |
20 | [redis--全局命令](https://github.com/wuxiaobo000111/markdown/blob/master/redis/redis%E5%85%A8%E5%B1%80%E5%91%BD%E4%BB%A4.md "redis--全局命令")
21 |
22 |
23 | [redis--pipeline](https://github.com/wuxiaobo000111/markdown/blob/master/redis/PipeLine.md "redis--pipeline")
24 |
25 |
26 | [redis--redis-benchmark详解](https://github.com/wuxiaobo000111/markdown/blob/master/redis/redis-benchmark%E8%AF%A6%E8%A7%A3.md "redis--redis-benchmark详解")
27 |
28 |
29 | [redis--事务和Lua](https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E4%BA%8B%E5%8A%A1%E5%92%8CLua.md "redis--事务和Lua")
30 |
31 |
32 | [redis--慢查询分析](
33 | https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E6%85%A2%E6%9F%A5%E8%AF%A2%E5%88%86%E6%9E%90.md "redis--全局命令")
34 |
35 |
36 |
37 | [redis--redis-cli详解](
38 | https://github.com/wuxiaobo000111/markdown/blob/master/redis/redis-cli%E8%AF%A6%E8%A7%A3.md
39 | "redis--redis-cli详解")
40 |
41 | [redis--HyperLogLog](https://github.com/wuxiaobo000111/markdown/blob/master/redis/HyperLogLog.md "redis--HyperLogLog")
42 |
43 |
44 | [redis--发布订阅](https://github.com/wuxiaobo000111/markdown/blob/master/redis/redis--%E5%8F%91%E5%B8%83%E8%AE%A2%E9%98%85.md "redis--发布定于")
45 |
46 |
47 | [redis--RDB和AOF](https://github.com/wuxiaobo000111/markdown/blob/master/redis/RDB%E5%92%8CAOF.md "redis--RDB和AOF")
48 |
49 | ## 主从复制
50 |
51 | [redis--如何配置主从](https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/%E5%A6%82%E4%BD%95%E9%85%8D%E7%BD%AE%E4%B8%BB%E4%BB%8E.md "redis--如何配置主从")
52 |
53 | [redis--主从复制拓扑结构](https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E7%9A%84%E6%8B%93%E6%89%91%E7%BB%93%E6%9E%84.md "redis--主从复制拓扑结构")
54 |
55 | [redis--主从复制原理](https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E7%9A%84%E5%8E%9F%E7%90%86.md "redis--主从复制原理")
56 |
57 | [redis--主从复制带来的问题](https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E4%B8%AD%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB%E5%B8%A6%E6%9D%A5%E7%9A%84%E9%97%AE%E9%A2%98.md "redis--RDB和AOF")
58 |
59 |
60 | ## 阻塞
61 |
62 |
63 | [redis--阻塞](
64 | https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E9%98%BB%E5%A1%9E/%E5%8F%91%E7%8E%B0%E9%98%BB%E5%A1%9E.md "redis--阻塞")
65 |
66 | # 哨兵
67 |
68 |
69 | [redis--如何配置redis哨兵](
70 | https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E5%93%A8%E5%85%B5/%E5%A6%82%E4%BD%95%E9%85%8D%E7%BD%AEredis%E5%93%A8%E5%85%B5.md "redis--如何配置redis哨兵.")
71 |
72 |
73 | [redis--哨兵配置说明](
74 | https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E5%93%A8%E5%85%B5/redis%E5%93%A8%E5%85%B5%E9%85%8D%E7%BD%AE%E8%AF%B4%E6%98%8E.md "redis--哨兵配置说明")
75 |
76 |
77 | [redis--sentinel命令](
78 | https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E5%93%A8%E5%85%B5/sentinel%E5%91%BD%E4%BB%A4.md "redis--sentinel命令")
79 |
80 |
81 | [redis--sentinel原理](
82 | https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E5%93%A8%E5%85%B5/%E5%93%A8%E5%85%B5%E5%8E%9F%E7%90%86.md "redis--sentinel原理")
83 |
84 | # 集群
85 |
86 |
87 | [redis--集群搭建](
88 | https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E9%9B%86%E7%BE%A4/redis%20cluster.md "redis--集群搭建")
89 |
90 | # 缓存设计
91 |
92 |
93 | [redis--缓存设计](
94 | https://github.com/wuxiaobo000111/markdown/blob/master/redis/%E7%BC%93%E5%AD%98%E8%AE%BE%E8%AE%A1/%E7%BC%93%E5%AD%98%E8%AE%BE%E8%AE%A1.md "redis--缓存设计")
--------------------------------------------------------------------------------
/catalog/spring.md:
--------------------------------------------------------------------------------
1 | # spring
2 |
3 |
4 | # 源码解析篇
5 |
6 | [Spring源码解析篇--配置文件的封装](https://github.com/wuxiaobo000111/markdown/blob/master/spring/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%B0%81%E8%A3%85.md "Spring源码解析篇--配置文件的封装") ClassPathResource类的继承关系。
7 |
8 | [Spring源码解析篇-spring核心类](https://github.com/wuxiaobo000111/markdown/blob/master/spring/spring%E6%A0%B8%E5%BF%83%E7%B1%BB.md "Spring源码解析篇--spring核心类") spring核心类的简单介绍
9 |
10 | [Spring源码解析篇--Spring注册解析的bean](https://github.com/wuxiaobo000111/markdown/blob/master/spring/Spring%E6%B3%A8%E5%86%8C%E8%A7%A3%E6%9E%90%E7%9A%84bean.md "Spring源码解析篇--Spring注册解析的bean") Spring注册解析的bean
11 |
12 | [Spring源码解析篇--Spring默认标签解析](https://github.com/wuxiaobo000111/markdown/blob/master/spring/Spring%E9%BB%98%E8%AE%A4%E6%A0%87%E7%AD%BE%E8%A7%A3%E6%9E%90.md "Spring源码解析篇--Spring默认标签解析") Spring默认标签解析
13 |
14 |
15 | [Spring源码解析篇--Spring默认标签中的自定义标签解析](https://github.com/wuxiaobo000111/markdown/blob/master/spring/Spring%E9%BB%98%E8%AE%A4%E6%A0%87%E7%AD%BE%E4%B8%AD%E7%9A%84%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%87%E7%AD%BE%E8%A7%A3%E6%9E%90.md "Spring源码解析篇--Spring默认标签中的自定义标签解析") Spring默认标签中的自定义标签解析
16 |
17 |
18 |
19 |
20 | [Spring源码解析篇--Spring自定义标签解析](https://github.com/wuxiaobo000111/markdown/blob/master/spring/Spring%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%87%E7%AD%BE%E8%A7%A3%E6%9E%90.md "Spring源码解析篇--Spring自定义标签解析") Spring自定义标签解析
21 |
22 |
--------------------------------------------------------------------------------
/catalog/springboot.md:
--------------------------------------------------------------------------------
1 | # springboot
2 |
3 |
4 | [springboot如何实现email发送](https://github.com/wuxiaobo000111/Java--apollo/blob/master/springboot/springboot%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0email%E5%8F%91%E9%80%81.md "springboot如何实现email发送]")
--------------------------------------------------------------------------------
/catalog/架构之路.md:
--------------------------------------------------------------------------------
1 |
2 | # 架构之路
3 |
4 | ## 技术相关
5 | [Redis--防击穿和雪崩](https://github.com/wuxiaobo000111/Java--apollo/blob/master/%E6%9E%B6%E6%9E%84%E4%B9%8B%E8%B7%AF/%E6%8A%80%E6%9C%AF%E7%9B%B8%E5%85%B3/Redis--%E9%98%B2%E5%87%BB%E7%A9%BF%E5%92%8C%E9%9B%AA%E5%B4%A9.md "Redis--防击穿和雪崩")
6 |
7 | ## 代码质量管理平台
8 |
9 | [代码质量管理平台SonarQube](https://github.com/wuxiaobo000111/Java--apollo/blob/master/%E6%9E%B6%E6%9E%84%E4%B9%8B%E8%B7%AF/%E4%BB%A3%E7%A0%81%E8%B4%A8%E9%87%8F%E7%AE%A1%E7%90%86%E5%B9%B3%E5%8F%B0SonarQube/%E4%BB%A3%E7%A0%81%E8%B4%A8%E9%87%8F%E7%AE%A1%E7%90%86%E5%B9%B3%E5%8F%B0SonarQube.md "代码质量管理平台SonarQube")
--------------------------------------------------------------------------------
/catalog/面试篇.md:
--------------------------------------------------------------------------------
1 | # 面试篇
2 |
3 | ## Spring
4 |
5 | [Spring--SpringIoc](https://github.com/wuxiaobo000111/Java--apollo/blob/master/%E9%9D%A2%E8%AF%95%E9%A2%98/Spring/SpringIoc.md "Spring--SpringIoc")
6 |
7 |
8 | [Spring--SpringBean循环创建](https://github.com/wuxiaobo000111/Java--apollo/blob/master/%E9%9D%A2%E8%AF%95%E9%A2%98/Spring/SpringBean%E5%BE%AA%E7%8E%AF%E5%88%9B%E5%BB%BA.md "Spring--SpringBean循环创建")
9 |
10 |
11 | [Spring--几种代理的实现方式](https://github.com/wuxiaobo000111/Java--apollo/blob/master/%E9%9D%A2%E8%AF%95%E9%A2%98/Spring/%E5%87%A0%E7%A7%8D%E4%BB%A3%E7%90%86%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F.md "Spring--几种代理的实现方式")
12 |
13 | [Spring--SpringAOP](https://github.com/wuxiaobo000111/Java--apollo/blob/master/%E9%9D%A2%E8%AF%95%E9%A2%98/Spring/SpringAOP.md "Spring--SpringAOP")
14 |
15 | [Spring--Spring事务](https://github.com/wuxiaobo000111/Java--apollo/blob/master/%E9%9D%A2%E8%AF%95%E9%A2%98/Spring/Spring%E4%BA%8B%E5%8A%A1.md "Spring--Spring事务")
--------------------------------------------------------------------------------
/jdk/JVM相关/JDK7和JDK8的内存区域划分.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | 
4 |
5 | 
--------------------------------------------------------------------------------
/jdk/NIO/NIO/NIO之 通道之间的数据传输.md:
--------------------------------------------------------------------------------
1 | 转载于:
2 |
3 |
4 | 在Java NIO中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel(译者注:channel中文常译作通道)传输到另外一个channel。
5 |
6 |
7 | # transferFrom()
8 |
9 | FileChannel的transferFrom()方法可以将数据从源通道传输到FileChannel中(译者注:这个方法在JDK文档中的解释为将字节从给定的可读取字节通道传输到此通道的文件中)。下面是一个简单的例子:
10 |
11 |
12 | ```java
13 | RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
14 | FileChannel fromChannel = fromFile.getChannel();
15 | RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
16 | FileChannel toChannel = toFile.getChannel();
17 | long position = 0;
18 | long count = fromChannel.size();
19 | toChannel.transferFrom(position, count, fromChannel);
20 | ```
21 |
22 | 方法的输入参数position表示从position处开始向目标文件写入数据,count表示最多传输的字节数。如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数。此外要注意,在SoketChannel的实现中,SocketChannel只会传输此刻准备好的数据(可能不足count字节)。因此,SocketChannel可能不会将请求的所有数据(count个字节)全部传输到FileChannel中。
23 |
24 |
25 | # transferTo()
26 |
27 | transferTo()方法将数据从FileChannel传输到其他的channel中。下面是一个简单的例子:
28 |
29 |
30 | ```java
31 |
32 | RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
33 | FileChannel fromChannel = fromFile.getChannel();
34 | RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
35 | FileChannel toChannel = toFile.getChannel();
36 | long position = 0;
37 | long count = fromChannel.size();
38 | fromChannel.transferTo(position, count, toChannel);
39 | ```
40 |
41 | 上面所说的关于SocketChannel的问题在transferTo()方法中同样存在。SocketChannel会一直传输数据直到目标buffer被填满。
--------------------------------------------------------------------------------
/jdk/NIO/NIO/NIO之Channel.md:
--------------------------------------------------------------------------------
1 | 转载于:https://ifeve.com/channels/
2 |
3 | # 概述
4 |
5 | NIO和IO的区别
6 |
7 | ```text
8 | 1. 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
9 |
10 | 2. 通道可以异步地读写。
11 |
12 | 3. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。
13 | ```
14 |
15 |
16 | 
17 |
18 |
19 | # Channel类型
20 |
21 |
22 | ```text
23 | 1. FileChannel : 从文件中读写数据。
24 |
25 | 2. DatagramChannel : 能通过UDP读写网络中的数据。
26 |
27 | 3. SocketChannel : 能通过TCP读写网络中的数据。
28 |
29 | 4. ServerSocketChannel : 可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
30 | ```
31 |
32 | # 给出一个示例
33 |
34 |
35 | ```java
36 |
37 |
38 | public static void main(String[] args) throws Exception {
39 | RandomAccessFile aFile = new RandomAccessFile("文件名", "rw");
40 | FileChannel inChannel = aFile.getChannel();
41 | ByteBuffer buf = ByteBuffer.allocate(1024);
42 | int bytesRead = inChannel.read(buf);
43 | while (bytesRead != -1) {
44 | System.out.println("Read " + bytesRead);
45 | buf.flip();
46 | while(buf.hasRemaining()){
47 | System.out.print((char) buf.get());
48 | }
49 | buf.clear();
50 | bytesRead = inChannel.read(buf);
51 | }
52 | aFile.close();
53 | }
54 | ```
55 |
--------------------------------------------------------------------------------
/jdk/NIO/NIO/NIO之FileChannel.md:
--------------------------------------------------------------------------------
1 | 转载于:https://ifeve.com/file-channel/
2 |
3 | # 概述
4 |
5 | Java NIO中的FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。
6 |
7 |
8 | # 示例
9 |
10 | ```java
11 |
12 | public static void test01 () throws Exception {
13 | RandomAccessFile aFile = new RandomAccessFile("文件路径", "rw");
14 | FileChannel inChannel = aFile.getChannel();
15 | ByteBuffer buf = ByteBuffer.allocate(1024);
16 | FileOutputStream fileOutputStream = new FileOutputStream(new File("D:\\wuxiaobo.log"));
17 | FileChannel fileOutputStreamChannel = fileOutputStream.getChannel();
18 | int bytesRead = inChannel.read(buf);
19 | while (bytesRead != -1) {
20 | buf.flip();
21 | while(buf.hasRemaining()){
22 | fileOutputStreamChannel.write(buf);
23 | }
24 | buf.clear();
25 | bytesRead = inChannel.read(buf);
26 | }
27 | aFile.close();
28 | }
29 | ```
30 |
31 |
32 | # 其他方法
33 |
34 |
35 | ## position
36 |
37 |
38 | 有时可能需要在FileChannel的某个特定位置进行数据的读/写操作。可以通过调用position()方法获取FileChannel的当前位置。也可以通过调用position(long pos)方法设置FileChannel的当前位置。这里有两个例子:
39 | ```java
40 | long pos = channel.position();
41 | channel.position(pos +123);
42 | ```
43 | 如果将位置设置在文件结束符之后,然后试图从文件通道中读取数据,读方法将返回-1 —— 文件结束标志。如果将位置设置在文件结束符之后,然后向通道中写数据,文件将撑大到当前位置并写入数据。这可能导致“文件空洞”,磁盘上物理文件中写入的数据间有空隙。
44 |
45 | ## size
46 |
47 | FileChannel实例的size()方法将返回该实例所关联文件的大小。如:
48 |
49 |
50 | ```java
51 | long fileSize = channel.size();
52 | ```
53 |
54 | ## truncate
55 |
56 | 可以使用FileChannel.truncate()方法截取一个文件。截取文件时,文件将中指定长度后面的部分将被删除。如:
57 |
58 | ```java
59 | channel.truncate(1024);
60 | // 这个例子截取文件的前1024个字节。
61 | ```
62 |
63 |
64 | ## force方法
65 |
66 | FileChannel.force()方法将通道里尚未写入磁盘的数据强制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。要保证这一点,需要调用force()方法。force()方法有一个boolean类型的参数,指明是否同时将文件元数据(权限信息等)写到磁盘上。下面的例子同时将文件数据和元数据强制写到磁盘上:
67 |
68 | ```java
69 | channel.force(true);
70 | ```
71 |
--------------------------------------------------------------------------------
/jdk/NIO/NIO/NIO之Pipe.md:
--------------------------------------------------------------------------------
1 | 转载于:https://ifeve.com/pipe/
2 |
3 | # 概述
4 |
5 | Java NIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。
6 |
7 |
8 | 
9 |
10 |
11 | # 创建管道
12 |
13 | ```java
14 | Pipe pipe = Pipe.open();
15 |
16 | ```
17 |
18 | # 向管道写数据
19 |
20 | ```java
21 | Pipe.SinkChannel sinkChannel = pipe.sink();
22 | String newData = "New String to write to file..." + System.currentTimeMillis();
23 | ByteBuffer buf = ByteBuffer.allocate(48);
24 | buf.clear();
25 | buf.put(newData.getBytes());
26 | buf.flip();
27 |
28 | while(buf.hasRemaining()) {
29 | sinkChannel.write(buf);
30 | }
31 |
32 |
33 | ```
34 |
35 | # 从管道读数据
36 |
37 | ```java
38 | Pipe.SourceChannel sourceChannel = pipe.source();
39 | ByteBuffer buf = ByteBuffer.allocate(48);
40 | int bytesRead = sourceChannel.read(buf);
41 | ```
--------------------------------------------------------------------------------
/jdk/NIO/NIO/NIO之Scatter和Gather.md:
--------------------------------------------------------------------------------
1 | 转载于: https://ifeve.com/java-nio-scattergather/
2 |
3 | Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作。
4 | 分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中。因此,Channel将从Channel中读取的数据“分散(scatter)”到多个Buffer中。
5 | 聚集(gather)写入Channel是指在写操作时将多个buffer的数据写入同一个Channel,因此,Channel 将多个Buffer中的数据“聚集(gather)”后发送到Channel。
6 | scatter / gather经常用于需要将传输的数据分开处理的场合,例如传输一个由消息头和消息体组成的消息,你可能会将消息体和消息头分散到不同的buffer中,这样你可以方便的处理消息头和消息体。
7 |
8 |
9 | # scatter
10 |
11 |
12 | 
13 |
14 | 代码示例
15 |
16 | ```java
17 | ByteBuffer header = ByteBuffer.allocate(128);
18 | ByteBuffer body = ByteBuffer.allocate(1024);
19 | ByteBuffer[] bufferArray = { header, body };
20 | channel.read(bufferArray);
21 | ```
22 | 注意buffer首先被插入到数组,然后再将数组作为channel.read() 的输入参数。read()方法按照buffer在数组中的顺序将从channel中读取的数据写入到buffer,当一个buffer被写满后,channel紧接着向另一个buffer中写。
23 | Scattering Reads在移动下一个buffer前,必须填满当前的buffer,这也意味着它不适用于动态消息(译者注:消息大小不固定)。换句话说,如果存在消息头和消息体,消息头必须完成填充(例如 128byte),Scattering Reads才能正常工作。
24 |
25 |
26 | # gather
27 |
28 | 
29 |
30 |
31 | 示例代码:
32 |
33 | ```java
34 | ByteBuffer header = ByteBuffer.allocate(128);
35 | ByteBuffer body = ByteBuffer.allocate(1024);
36 | //write data into buffers
37 | ByteBuffer[] bufferArray = { header, body };
38 | channel.write(bufferArray);
39 | ```
40 |
41 | buffers数组是write()方法的入参,write()方法会按照buffer在数组中的顺序,将数据写入到channel,注意只有position和limit之间的数据才会被写入。因此,如果一个buffer的容量为128byte,但是仅仅包含58byte的数据,那么这58byte的数据将被写入到channel中。因此与Scattering Reads相反,Gathering Writes能较好的处理动态消息。
--------------------------------------------------------------------------------
/jdk/NIO/NIO/NIO之ServerSocketChannel.md:
--------------------------------------------------------------------------------
1 |
2 | # 示例代码
3 |
4 | ```java
5 | import java.io.IOException;
6 | import java.net.InetSocketAddress;
7 | import java.nio.ByteBuffer;
8 | import java.nio.channels.SelectionKey;
9 | import java.nio.channels.Selector;
10 | import java.nio.channels.ServerSocketChannel;
11 | import java.nio.channels.SocketChannel;
12 | import java.util.Iterator;
13 |
14 | public class NIOServer {
15 |
16 | /**
17 | * 选择器
18 | */
19 | private Selector selector;
20 |
21 | /**
22 | * 通道
23 | */
24 | ServerSocketChannel serverSocketChannel;
25 |
26 | public void initServer(int port) throws IOException
27 | {
28 | //打开一个通道
29 | serverSocketChannel = ServerSocketChannel.open();
30 |
31 | //通道设置非阻塞
32 | serverSocketChannel.configureBlocking(false);
33 |
34 | //绑定端口号
35 | serverSocketChannel.socket().bind(new InetSocketAddress("localhost", port));
36 |
37 | //注册
38 | this.selector = Selector.open();
39 | serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
40 | }
41 |
42 | public void listen() throws IOException
43 | {
44 | System.out.println("server started succeed!");
45 |
46 | while (true)
47 | {
48 | selector.select();
49 | Iterator ite = selector.selectedKeys().iterator();
50 | while (ite.hasNext())
51 | {
52 | SelectionKey key = ite.next();
53 | if (key.isAcceptable())
54 | {
55 | SocketChannel channel = serverSocketChannel.accept();
56 | channel.configureBlocking(false);
57 | channel.register(selector, SelectionKey.OP_READ);
58 | }
59 | else if (key.isReadable())
60 | {
61 | recvAndReply(key);
62 | }
63 | ite.remove();
64 | }
65 | }
66 | }
67 |
68 | public void recvAndReply(SelectionKey key) throws IOException
69 | {
70 | SocketChannel channel = (SocketChannel) key.channel();
71 | ByteBuffer buffer = ByteBuffer.allocate(256);
72 | int i = channel.read(buffer);
73 | if (i != -1)
74 | {
75 | String msg = new String(buffer.array()).trim();
76 | System.out.println("NIO server received message = " + msg);
77 | System.out.println("NIO server reply = " + msg);
78 | channel.write(ByteBuffer.wrap( msg.getBytes()));
79 | }
80 | else
81 | {
82 | channel.close();
83 | }
84 | }
85 |
86 | public static void main(String[] args) throws IOException
87 | {
88 | NIOServer server = new NIOServer();
89 | server.initServer(10000);
90 | server.listen();
91 | }
92 |
93 | }
94 |
95 | ```
--------------------------------------------------------------------------------
/jdk/NIO/NIO/NIO之SocketChannel.md:
--------------------------------------------------------------------------------
1 | # 概述
2 | Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道。可以通过以下2种方式创建SocketChannel。
3 |
4 |
5 | # 代码示例
6 |
7 | ```java
8 | import java.io.IOException;
9 | import java.net.InetSocketAddress;
10 | import java.nio.ByteBuffer;
11 | import java.nio.channels.SocketChannel;
12 |
13 | public class NIOClient {
14 | /**
15 | * 通道
16 | */
17 | SocketChannel channel;
18 |
19 | public void initClient(String host, int port) throws IOException
20 | {
21 | //构造socket连接
22 | InetSocketAddress servAddr = new InetSocketAddress(host, port);
23 |
24 | //打开连接
25 | this.channel = SocketChannel.open(servAddr);
26 | }
27 |
28 | public void sendAndRecv(String words) throws IOException
29 | {
30 | byte[] msg = new String(words).getBytes();
31 | ByteBuffer buffer = ByteBuffer.wrap(msg);
32 | System.out.println("Client sending: " + words);
33 | channel.write(buffer);
34 | buffer.clear();
35 | channel.read(buffer);
36 | System.out.println("Client received: " + new String(buffer.array()).trim());
37 |
38 | channel.close();
39 | }
40 |
41 | public static void main(String[] args) throws IOException
42 | {
43 | NIOClient client = new NIOClient();
44 | client.initClient("localhost", 10000);
45 | client.sendAndRecv("I am a client");
46 | }
47 | }
48 |
49 | ```
--------------------------------------------------------------------------------
/jdk/NIO/三种IO的总结.md:
--------------------------------------------------------------------------------
1 | >https://blog.csdn.net/caohongshuang/article/details/79455391
2 |
3 | # BIO
4 | ## 传统的BIO编程
5 |
6 | 网络编程的基本模型是C/S模型,即两个进程间的通信。
7 |
8 | 服务端提供IP和监听端口,客户端通过连接操作想服务端监听的地址发起连接请求,通过三次握手连接,如果连接成功建立,双方就可以通过套接字进行通信。
9 |
10 | 传统的同步阻塞模型开发中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作。连接成功后,双方通过输入和输出流进行同步阻塞式通信。
11 |
12 | 简单的描述一下BIO的服务端通信模型:采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,它接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理没处理完成后,通过输出流返回应答给客户端,线程销毁。即典型的一请求一应答模型。
13 |
14 |
15 |
16 | 
17 |
18 | 该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,Java中的线程也是比较宝贵的系统资源,线程数量快速膨胀后,系统的性能将急剧下降,随着访问量的继续增大,系统最终就死-掉-了。
19 |
20 | # NIO
21 |
22 | JDK 1.4中的java.nio.*包中引入新的Java I/O库,其目的是提高速度。实际上,“旧”的I/O包已经使用NIO重新实现过,即使我们不显式的使用NIO编程,也能从中受益。速度的提高在文件I/O和网络I/O中都可能会发生,但本文只讨论后者。
23 |
24 | NIO我们一般认为是New I/O(也是官方的叫法),因为它是相对于老的I/O类库新增的(其实在JDK 1.4中就已经被引入了,但这个名词还会继续用很久,即使它们在现在看来已经是“旧”的了,所以也提示我们在命名时,需要好好考虑),做了很大的改变。但民间跟多人称之为Non-block I/O,即非阻塞I/O,因为这样叫,更能体现它的特点。而下文中的NIO,不是指整个新的I/O库,而是非阻塞I/O。
25 |
26 | NIO提供了与传统BIO模型中的Socket和ServerSocket相对应的SocketChannel和ServerSocketChannel两种不同的套接字通道实现。新增的着两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用NIO的非阻塞模式来开发。
27 |
28 | ## 基础知识
29 |
30 | ### 缓冲区 Buffer
31 |
32 | Buffer是一个对象,包含一些要写入或者读出的数据。在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的;在写入数据时,也是写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。缓冲区实际上是一个数组,并提供了对数据结构化访问以及维护读写位置等信息。具体的缓存区有这些:ByteBuffe、CharBuffer、 ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。他们实现了相同的接口:Buffer。
33 |
34 | 
35 |
36 | ### 通道 Channel
37 |
38 | 我们对数据的读取和写入要通过Channel,它就像水管一样,是一个通道。通道不同于流的地方就是通道是双向的,可以用于读、写和同时读写操作。底层的操作系统的通道一般都是全双工的,所以全双工的Channel比流能更好的映射底层操作系统的API。Channel主要分两大类:SelectableChannel:用户网络读写和FileChannel:用于文件操作后面代码会涉及的ServerSocketChannel和SocketChannel都是SelectableChannel的子类。
39 |
40 |
41 | 
42 |
43 |
44 | ### 多路复用器 Selector
45 |
46 | Selector是Java NIO 编程的基础。Selector提供选择已经就绪的任务的能力:Selector会不断轮询注册在其上的Channel,如果某个Channel上面发生读或者写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的I/O操作。一个Selector可以同时轮询多个Channel,因为JDK使用了epoll()代替传统的select实现,所以没有最大连接句柄1024/2048的限制。所以,只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端。
47 |
48 | # AIO
49 |
50 | NIO 2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。异步的套接字通道时真正的异步非阻塞I/O,对应于UNIX网络编程中的事件驱动I/O(AIO)。他不需要过多的Selector对注册的通道进行轮询即可实现异步读写,从而简化了NIO的编程模型。
--------------------------------------------------------------------------------
/jdk/jdk8/Lambda.md:
--------------------------------------------------------------------------------
1 | # Lambda表达式的三部分
2 |
3 | ```java
4 | 1. 参数列表
5 | 2. 箭头:把参数列表和Lambda主体分割开。
6 | 3. Lambda
7 |
8 | filterGreenApples(apples,apple -> "green".equals(apple.getColor()));
9 |
10 | 其中,apple就是参数,"green".equals(apple.getColor())是Lambda主体。
11 | ```
12 |
13 | # 函数式接口
14 |
15 | > 只是定义一个抽象方法的接口。
--------------------------------------------------------------------------------
/jdk/jdk8/使用Optional.md:
--------------------------------------------------------------------------------
1 | ```java
2 | package com.bobo.basic.jdk8.chapter7;
3 |
4 | import com.bobo.basic.jdk8.Dish;
5 |
6 | import java.util.Optional;
7 |
8 | public class Optional类 {
9 |
10 | public static void test01 () {
11 | Dish dish = new Dish("pork", false, 800, Dish.Type.MEAT);
12 | Optional optionalDish = Optional.of(dish);
13 | if (optionalDish.isPresent()) {
14 | System.out.println(dish.toString());
15 | } else {
16 | System.out.println("dis is not exits");
17 | }
18 | optionalDish = Optional.empty();
19 | if (optionalDish.isPresent()) {
20 | System.out.println(optionalDish.get().toString());
21 | } else {
22 | System.out.println(optionalDish);
23 | }
24 | }
25 | public static void main(String[] args) {
26 | test01();
27 | }
28 | }
29 |
30 | ```
--------------------------------------------------------------------------------
/jdk/jdk8/并行流.md:
--------------------------------------------------------------------------------
1 | ```java
2 | package com.bobo.basic.jdk8.chapter7;
3 |
4 | import java.util.stream.IntStream;
5 | import java.util.stream.Stream;
6 |
7 | public class 并行流 {
8 |
9 |
10 | /**
11 | * 演示如何使用并行流
12 | * 注意共享变量的问题,因为是并行计算,千万不要出现共享变量
13 | */
14 | public static void test01 () {
15 | Long aLong = Stream.iterate(1L, i -> i + 1).limit(100).parallel().reduce(0L, Long::sum);
16 | System.out.println(aLong);
17 | int reduce = IntStream.iterate(1, i -> i + 1).limit(100).parallel().reduce(0, (int1, int2) -> int1 + int2);
18 | System.out.println(reduce);
19 | }
20 | public static void main(String[] args) {
21 | test01();
22 | }
23 | }
24 |
25 | ```
--------------------------------------------------------------------------------
/jdk/jdk8/日期类/操作解析格式化日期.md:
--------------------------------------------------------------------------------
1 | ```java
2 | package com.bobo.basic.jdk8.date;
3 |
4 | import java.time.Duration;
5 | import java.time.Instant;
6 | import java.time.LocalDate;
7 | import java.time.LocalDateTime;
8 | import java.time.LocalTime;
9 | import java.time.Period;
10 | import java.time.temporal.ChronoField;
11 |
12 | /**
13 | * 关于java8中的日期类:
14 | * LocalDate, LocalTime,Instant,Duration和Period 最最最简单的使用
15 | */
16 | public class DateTest {
17 |
18 | /**
19 | * LocalDate日期类
20 | */
21 | public static void test01() {
22 | LocalDate localDate = LocalDate.of(2019, 4, 30);
23 | System.out.println(localDate.toString());
24 | localDate = LocalDate.now();
25 | System.out.println(localDate.toString());
26 | //使用TemporalField来去读LocalDate的值
27 | int year = localDate.get(ChronoField.YEAR);
28 | System.out.println("year: " + year);
29 | }
30 |
31 | /**
32 | * LocalTime的用法
33 | */
34 | public static void test02() {
35 | LocalTime localTime = LocalTime.of(15, 31, 20);
36 | System.out.println(localTime.toString());
37 | int hour = localTime.getHour();
38 | int minute = localTime.getMinute();
39 | int second = localTime.getSecond();
40 | System.out.println("hour:" + hour + ", minute: " + minute + ", second: " + second);
41 | LocalTime parse = LocalTime.parse("15:32:00");
42 | System.out.println(parse.toString());
43 | }
44 |
45 | /**
46 | * LocalDateTime的用法
47 | */
48 | public static void test03() {
49 | LocalDateTime localDateTime = LocalDateTime.now();
50 | System.out.println(localDateTime.toString());
51 | LocalDate localDate = LocalDate.of(2019, 4, 30);
52 | LocalTime localTime = LocalTime.of(15, 31, 20);
53 | localDateTime = LocalDateTime.of(localDate, localTime);
54 | System.out.println(localDateTime.toString());
55 | System.out.println(localDateTime.toLocalDate().toString() + " " + localDateTime.toLocalTime().toString());
56 | }
57 |
58 | /**
59 | * Instant的用法
60 | */
61 | public static void test04() {
62 | //从1970年1月1日之后加上
63 | Instant instant = Instant.ofEpochSecond(3);
64 | System.out.println(instant.toString());
65 | //注意这里会抛出异常信息
66 | int i = Instant.now().get(ChronoField.DAY_OF_MONTH);
67 | System.out.println(i);
68 | }
69 |
70 | /**
71 | * Duration的用法:主要用于以秒或者是纳秒来衡量时间的长短。如果需要比较日期,则可以使用Period类
72 | */
73 | public static void test05() {
74 | Duration between = Duration.between(LocalTime.of(15, 46, 0), LocalTime.now());
75 | System.out.println(between.getSeconds());
76 | Period period = Period.between(LocalDate.of(2018, 4, 30), LocalDate.of(2019, 3, 29));
77 | System.out.println(period.getYears());
78 | System.out.println(period.getMonths());
79 | System.out.println(period.getDays());
80 | }
81 |
82 | public static void main(String[] args) {
83 | test05();
84 | }
85 | }
86 | ```
--------------------------------------------------------------------------------
/jdk/jdk8/日期类/日期类.md:
--------------------------------------------------------------------------------
1 | ```java
2 | package com.bobo.basic.jdk8.date;
3 |
4 | import java.time.Duration;
5 | import java.time.Instant;
6 | import java.time.LocalDate;
7 | import java.time.LocalDateTime;
8 | import java.time.LocalTime;
9 | import java.time.Period;
10 | import java.time.temporal.ChronoField;
11 |
12 | /**
13 | * 关于java8中的日期类:
14 | * LocalDate, LocalTime,Instant,Duration和Period 最最最简单的使用
15 | */
16 | public class DateTest {
17 |
18 | /**
19 | * LocalDate日期类
20 | */
21 | public static void test01() {
22 | LocalDate localDate = LocalDate.of(2019, 4, 30);
23 | System.out.println(localDate.toString());
24 | localDate = LocalDate.now();
25 | System.out.println(localDate.toString());
26 | //使用TemporalField来去读LocalDate的值
27 | int year = localDate.get(ChronoField.YEAR);
28 | System.out.println("year: " + year);
29 | }
30 |
31 | /**
32 | * LocalTime的用法
33 | */
34 | public static void test02() {
35 | LocalTime localTime = LocalTime.of(15, 31, 20);
36 | System.out.println(localTime.toString());
37 | int hour = localTime.getHour();
38 | int minute = localTime.getMinute();
39 | int second = localTime.getSecond();
40 | System.out.println("hour:" + hour + ", minute: " + minute + ", second: " + second);
41 | LocalTime parse = LocalTime.parse("15:32:00");
42 | System.out.println(parse.toString());
43 | }
44 |
45 | /**
46 | * LocalDateTime的用法
47 | */
48 | public static void test03() {
49 | LocalDateTime localDateTime = LocalDateTime.now();
50 | System.out.println(localDateTime.toString());
51 | LocalDate localDate = LocalDate.of(2019, 4, 30);
52 | LocalTime localTime = LocalTime.of(15, 31, 20);
53 | localDateTime = LocalDateTime.of(localDate, localTime);
54 | System.out.println(localDateTime.toString());
55 | System.out.println(localDateTime.toLocalDate().toString() + " " + localDateTime.toLocalTime().toString());
56 | }
57 |
58 | /**
59 | * Instant的用法
60 | */
61 | public static void test04() {
62 | //从1970年1月1日之后加上
63 | Instant instant = Instant.ofEpochSecond(3);
64 | System.out.println(instant.toString());
65 | //注意这里会抛出异常信息
66 | int i = Instant.now().get(ChronoField.DAY_OF_MONTH);
67 | System.out.println(i);
68 | }
69 |
70 | /**
71 | * Duration的用法:主要用于以秒或者是纳秒来衡量时间的长短。如果需要比较日期,则可以使用Period类
72 | */
73 | public static void test05() {
74 | Duration between = Duration.between(LocalTime.of(15, 46, 0), LocalTime.now());
75 | System.out.println(between.getSeconds());
76 | Period period = Period.between(LocalDate.of(2018, 4, 30), LocalDate.of(2019, 3, 29));
77 | System.out.println(period.getYears());
78 | System.out.println(period.getMonths());
79 | System.out.println(period.getDays());
80 | }
81 |
82 | public static void main(String[] args) {
83 | test05();
84 | }
85 | }
86 | ```
--------------------------------------------------------------------------------
/jdk/jdk8/流/CompletableFuture.md:
--------------------------------------------------------------------------------
1 | ```java
2 | package com.bobo.basic.jdk8.chapter11;
3 |
4 | public class DelayUtil {
5 |
6 | public static void delay () {
7 | try {
8 | Thread.sleep(1000L);
9 | } catch (InterruptedException e) {
10 | e.printStackTrace();
11 | }
12 | }
13 | }
14 |
15 | package com.bobo.basic.jdk8.chapter11;
16 |
17 | import java.util.Random;
18 | import java.util.concurrent.CompletableFuture;
19 | import java.util.concurrent.ConcurrentHashMap;
20 | import java.util.concurrent.Future;
21 | import java.util.concurrent.locks.Lock;
22 | import java.util.concurrent.locks.ReentrantLock;
23 |
24 | public class Shop {
25 |
26 | private String name;
27 |
28 | public void setName(String name) {
29 | this.name = name;
30 | }
31 |
32 | public String getName() {
33 | return name;
34 | }
35 |
36 | public Shop() {
37 |
38 | }
39 | public Shop(String name) {
40 | this.name = name;
41 | }
42 |
43 | public static void main(String[] args) throws Exception {
44 | Shop shop = new Shop("BestShop");
45 | Future myFavoriteProduct = shop.getPriceAsync("my favorite product");
46 | // 这个get注意:要么获取到返回值,如果没有返回值的话就会在一直阻塞中。
47 | Double aDouble = myFavoriteProduct.get();
48 | System.out.println("price: "+ aDouble);
49 | }
50 | public double getPrice (String product) {
51 | return calculatePrice(product);
52 | }
53 |
54 | public Future getPriceAsync (String product) {
55 | CompletableFuture future = new CompletableFuture<>();
56 | new Thread(() ->{
57 | try {
58 | double calculatePrice = calculatePrice(product);
59 | future.complete(calculatePrice);
60 | }catch (Exception e) {
61 | //异常处理
62 | future.completeExceptionally(e);
63 | }
64 | }).start();
65 |
66 | ReentrantLock lock = new ReentrantLock();
67 | lock.lock();
68 | return future;
69 | }
70 | private double calculatePrice(String product) {
71 | DelayUtil.delay();
72 | Random random = new Random();
73 | return random.nextDouble() * product.charAt(0) + product.charAt(1);
74 | }
75 |
76 |
77 |
78 | }
79 |
80 |
81 | ```
--------------------------------------------------------------------------------
/jdk/jdk8/流/分区.md:
--------------------------------------------------------------------------------
1 | ```java
2 | package com.bobo.basic.jdk8.chapter6;
3 |
4 | import com.bobo.basic.jdk8.Dish;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Arrays;
8 | import java.util.List;
9 | import java.util.Map;
10 | import java.util.stream.Collectors;
11 |
12 | public class 分区 {
13 |
14 |
15 | public static List menu = new ArrayList<>();
16 |
17 | static {
18 | menu = Arrays.asList(
19 | new Dish("pork", false, 800, Dish.Type.MEAT),
20 | new Dish("beef", false, 700, Dish.Type.MEAT),
21 | new Dish("chickren", false, 400, Dish.Type.MEAT),
22 | new Dish("french fries", true, 530, Dish.Type.OTHER),
23 | new Dish("rice", true, 350, Dish.Type.OTHER),
24 | new Dish("season fruit", true, 120, Dish.Type.OTHER),
25 | new Dish("pizza", true, 550, Dish.Type.OTHER),
26 | new Dish("prawns", false, 300, Dish.Type.FISH),
27 | new Dish("salmon", false, 450, Dish.Type.FISH)
28 | );
29 | }
30 |
31 |
32 |
33 |
34 | public static void test01 () {
35 | Map> collect = menu.stream().collect(Collectors.partitioningBy(Dish::isVegetarian));
36 | System.out.println(collect.toString());
37 | }
38 |
39 | public static void test02 () {
40 | Map>> collect = menu.stream().collect(Collectors.partitioningBy(Dish::isVegetarian, Collectors.groupingBy(Dish::getType)));
41 | System.out.println(collect);
42 | }
43 |
44 | /**
45 | * 什么是分区:分区是分组的特殊情况,由一个谓词(返回一个布尔值的函数)作为分类函数,被称为分区函数。分区函数返回一个布尔值,
46 | *分区最多只能分成为两组,一组是true,一组是false.
47 | *
48 | * 分区的好处:
49 | * 保留了分区函数返回true或者false两套流元素列表。同时提供了一个重载的版本。可以产生一个二级map
50 | * @param args
51 | */
52 | public static void main(String[] args) {
53 | test01();
54 | }
55 | }
56 |
57 | ```
--------------------------------------------------------------------------------
/jdk/jdk8/流/分组.md:
--------------------------------------------------------------------------------
1 | ```java
2 | package com.bobo.basic.jdk8.chapter6;
3 |
4 | import com.bobo.basic.jdk8.Dish;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Arrays;
8 | import java.util.Comparator;
9 | import java.util.List;
10 | import java.util.Map;
11 | import java.util.Optional;
12 | import java.util.stream.Collectors;
13 |
14 | /**
15 | * @author wuxiaobo
16 | */
17 | public class 分组 {
18 | public static List menu = new ArrayList<>();
19 |
20 | public static enum CaloricLevel {
21 | DIET,
22 | NORMAL,
23 | FAT
24 | };
25 | static {
26 | menu = Arrays.asList(
27 | new Dish("pork", false, 800, Dish.Type.MEAT),
28 | new Dish("beef", false, 700, Dish.Type.MEAT),
29 | new Dish("chickren", false, 400, Dish.Type.MEAT),
30 | new Dish("french fries", true, 530, Dish.Type.OTHER),
31 | new Dish("rice", true, 350, Dish.Type.OTHER),
32 | new Dish("season fruit", true, 120, Dish.Type.OTHER),
33 | new Dish("pizza", true, 550, Dish.Type.OTHER),
34 | new Dish("prawns", false, 300, Dish.Type.FISH),
35 | new Dish("salmon", false, 450, Dish.Type.FISH)
36 | );
37 | }
38 |
39 | /**
40 | * 这个例子是个一级分类
41 | * Collectors.groupingBy参数中叫做分类函数,
42 | */
43 | public static void test01 () {
44 | Map> collect = menu.stream().collect(Collectors.groupingBy(Dish::getType));
45 | System.out.println(collect.toString());
46 |
47 | System.out.println("====== 一道华丽的分割线 =======");
48 | Map> listMap = menu.stream().collect(Collectors.groupingBy(dish -> {
49 | if (dish.getCalories() <= 400) {
50 | return CaloricLevel.DIET;
51 | } else if (dish.getCalories() <= 700) {
52 | return CaloricLevel.NORMAL;
53 | } else {
54 | return CaloricLevel.FAT;
55 | }
56 | }));
57 |
58 | System.out.println(listMap.toString());
59 | }
60 |
61 |
62 | /**
63 | * 多级分类
64 | */
65 | public static void test02 () {
66 | Map>> collect = menu.stream().collect(Collectors.groupingBy(Dish::getType, Collectors.groupingBy(
67 | dish -> {
68 | if (dish.getCalories() <= 400) {
69 | return CaloricLevel.DIET;
70 | } else if (dish.getCalories() <= 700) {
71 | return CaloricLevel.NORMAL;
72 | } else {
73 | return CaloricLevel.FAT;
74 | }
75 | }
76 | )));
77 |
78 | System.out.println(collect);
79 | }
80 |
81 |
82 | /**
83 | *
84 | */
85 | public static void test03 () {
86 | Map collect = menu.stream().collect(Collectors.groupingBy(Dish::getType, Collectors.counting()));
87 | System.out.println(collect);
88 |
89 | System.out.println("======= 一道华丽的分割线 =======");
90 | Map> collect1 = menu.stream().collect(Collectors.groupingBy(Dish::getType, Collectors.maxBy(Comparator.comparingInt(Dish::getCalories))));
91 | System.out.println(collect1);
92 | }
93 |
94 | public static void main(String[] args) {
95 | test03();
96 | }
97 |
98 | }
99 |
100 | ```
--------------------------------------------------------------------------------
/jdk/jdk8/流/收集器.md:
--------------------------------------------------------------------------------
1 | ```java
2 | package com.bobo.basic.jdk8.chapter6;
3 |
4 |
5 | import com.bobo.basic.jdk8.Dish;
6 |
7 | import java.util.ArrayList;
8 | import java.util.Arrays;
9 | import java.util.Comparator;
10 | import java.util.IntSummaryStatistics;
11 | import java.util.List;
12 | import java.util.Optional;
13 | import java.util.stream.Collectors;
14 |
15 | /**
16 | * @author wuxiaobo
17 | */
18 | public class 收集器 {
19 |
20 | public static List menu = new ArrayList<>();
21 |
22 | static {
23 | menu = Arrays.asList(
24 | new Dish("pork", false, 800, Dish.Type.MEAT),
25 | new Dish("beef", false, 700, Dish.Type.MEAT),
26 | new Dish("chickren", false, 400, Dish.Type.MEAT),
27 | new Dish("french fries", true, 530, Dish.Type.OTHER),
28 | new Dish("rice", true, 350, Dish.Type.OTHER),
29 | new Dish("season fruit", true, 120, Dish.Type.OTHER),
30 | new Dish("pizza", true, 550, Dish.Type.OTHER),
31 | new Dish("prawns", false, 300, Dish.Type.FISH),
32 | new Dish("salmon", false, 450, Dish.Type.FISH)
33 | );
34 | }
35 |
36 | public static void test01 () {
37 | List collect = menu.stream().collect(Collectors.toList());
38 | System.out.println(collect);
39 | }
40 |
41 |
42 | public static void test02 () {
43 | Long aLong = menu.stream().map(Dish::getCalories).collect(Collectors.counting());
44 | System.out.println(aLong);
45 | }
46 |
47 |
48 | /**
49 | * 查找流中的最大值和最小值
50 | */
51 |
52 | public static void test03 () {
53 |
54 | // maxby获取最大值
55 | Optional collect = menu.stream().collect(Collectors.maxBy(Comparator.comparingInt(Dish::getCalories)));
56 | if (collect.isPresent()) {
57 | System.out.println(collect.get().toString());
58 | }
59 |
60 | System.out.println("====== 一道华丽的分割线 =======");
61 |
62 | // minby获取最小值
63 | Optional collect1 = menu.stream().collect(Collectors.minBy(Comparator.comparingInt(Dish::getCalories)));
64 | if (collect1.isPresent())
65 | {
66 | System.out.println(collect1.get().toString());
67 | }
68 | }
69 |
70 |
71 | /**
72 | * 汇总求总数
73 | */
74 | public static void test04 () {
75 | Integer collect = menu.stream().collect(Collectors.summingInt(Dish::getCalories));
76 | System.out.println(collect);
77 | }
78 |
79 |
80 | /**
81 | * 汇总,求平均数
82 | */
83 | public static void test05 () {
84 | Double collect = menu.stream().collect(Collectors.averagingInt(Dish::getCalories));
85 | System.out.println(collect);
86 | }
87 |
88 |
89 | /**
90 | * 通过summarizingInt可以计算出关于所有的数值操作
91 | * 其他类型用法相似
92 | */
93 | public static void test06 () {
94 | IntSummaryStatistics collect = menu.stream().collect(Collectors.summarizingInt(Dish::getCalories));
95 | System.out.println("average:"+collect.getAverage());
96 | System.out.println("sum:"+collect.getSum());
97 | }
98 |
99 |
100 | public static void test07 () {
101 | String collect = menu.stream().map(Dish::getName).collect(Collectors.joining(" "));
102 | System.out.println(collect);
103 | }
104 |
105 |
106 | /**
107 | * 所有的收集器都可以使用Collectors.reducing方法来实现。相当于一个工厂方法,是其他收集器的底层实现
108 | * 1.第一个参数是归约操作的起始值,也就是流中没有元素时候的返回值。
109 | * 2.第二个参数就是要计算的值。
110 | * 3.第三个是将两个项目累计成为一个同类型的值。
111 | *
112 | */
113 | public static void test08 () {
114 | Integer collect = menu.stream().collect(Collectors.reducing(0, Dish::getCalories, (i, j) -> i + j));
115 | System.out.println(collect);
116 |
117 | String collect1 = menu.stream().collect(Collectors.reducing("", Dish::getName, (name1, name2) -> name1 + " " + name2));
118 |
119 | System.out.println(collect1);
120 | }
121 | /**
122 | * 需要将流重组成为集合的时候,就会使用收集器
123 | * @param args
124 | */
125 | public static void main(String[] args) {
126 | test08();
127 | }
128 | }
129 |
130 | ```
--------------------------------------------------------------------------------
/jdk/jdk8/流/数值流.md:
--------------------------------------------------------------------------------
1 | ```java
2 | package com.bobo.basic.jdk8.chapter5;
3 |
4 | import com.bobo.basic.jdk8.Dish;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Arrays;
8 | import java.util.List;
9 | import java.util.OptionalInt;
10 | import java.util.stream.Collectors;
11 | import java.util.stream.IntStream;
12 |
13 | public class 数值流 {
14 |
15 | public static List menu = new ArrayList<>();
16 |
17 | static {
18 | menu = Arrays.asList(
19 | new Dish("pork", false, 800, Dish.Type.MEAT),
20 | new Dish("beef", false, 700, Dish.Type.MEAT),
21 | new Dish("chickren", false, 400, Dish.Type.MEAT),
22 | new Dish("french fries", true, 530, Dish.Type.OTHER),
23 | new Dish("rice", true, 350, Dish.Type.OTHER),
24 | new Dish("season fruit", true, 120, Dish.Type.OTHER),
25 | new Dish("pizza", true, 550, Dish.Type.OTHER),
26 | new Dish("prawns", false, 300, Dish.Type.FISH),
27 | new Dish("salmon", false, 450, Dish.Type.FISH)
28 | );
29 | }
30 |
31 |
32 | public static void main(String[] args) {
33 | test01();
34 | }
35 |
36 | /**
37 | * mapToInt方法实现了将流中的元素转化为int类型
38 | * boxed方法又实现了装箱操作
39 | * */
40 | public static void test01() {
41 | int sum = menu.stream().mapToInt(Dish::getCalories).sum();
42 | Integer integer = menu.stream().mapToInt(Dish::getCalories).boxed().findAny().get();
43 | System.out.println(integer);
44 |
45 | OptionalInt max = menu.stream().mapToInt(Dish::getCalories).max();
46 | }
47 |
48 | public static void test02() {
49 | IntStream intStream = IntStream.rangeClosed(1, 100);
50 | List collect = intStream.boxed().collect(Collectors.toList());
51 | System.out.println();
52 | }
53 | }
54 |
55 | ```
--------------------------------------------------------------------------------
/jdk/jdk8/流/流创建的几种方式.md:
--------------------------------------------------------------------------------
1 | ```java
2 | package com.bobo.basic.jdk8.chapter5;
3 |
4 |
5 | import java.io.IOException;
6 | import java.nio.charset.Charset;
7 | import java.nio.file.Files;
8 | import java.nio.file.Paths;
9 | import java.util.Arrays;
10 | import java.util.stream.Stream;
11 |
12 | /**
13 | * @author wuxiaobo
14 | */
15 | public class 流的创建 {
16 |
17 |
18 | /**
19 | * 通过Stream.of显式的创建一个流
20 | */
21 | public static void test01 () {
22 | Stream stringStream = Stream.of("Java 8", "Lambda", "In", "Action");
23 | stringStream.map(String::toUpperCase).forEach(System.out::println);
24 | }
25 |
26 |
27 | /**
28 | * 通过数组创建
29 | */
30 | public static void test02() {
31 | Integer[] array = {1,2,3,4,5};
32 | Arrays.stream(array).filter(integer -> integer.intValue()>2).forEach(System.out::println);
33 | }
34 |
35 |
36 | /**
37 | * 通过文件流的方式创建
38 | * @throws IOException
39 | */
40 | public static void test03 () throws IOException {
41 | Stream lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
42 | long count = lines.flatMap(line ->
43 | Arrays.stream(line.split(" "))).distinct().count();
44 | System.out.println(count);
45 | }
46 |
47 | /**
48 | * 通过Stream.iterate创建流
49 | */
50 | public static void test04 () {
51 | Stream.iterate(0,integer -> integer+2).limit(10).forEach(System.out::println);
52 | System.out.println("=======华丽的分割线");
53 | }
54 |
55 |
56 | /**
57 | * 通过 Stream.generate来创建流
58 | */
59 | public static void test05 () {
60 | Stream.generate(Math::random).limit(10).forEach(System.out::println);
61 | }
62 |
63 |
64 | public static void main(String[] args) {
65 | test04();
66 | }
67 |
68 | }
69 |
70 | ```
--------------------------------------------------------------------------------
/jdk/thread/CAS.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # 模型
4 | > CAS的全称是Compare And Swap 即比较交换,其算法核心思想如下执行函数:CAS(V,E,N)其包含3个参数: V表示要更新的变量,E表示预期值,N表示新值。
5 |
6 |
7 | > 如果V值等于E值,则将V的值设为N。若V值和E值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。通俗的理解就是CAS操作需要我们提供一个期望值,当期望值与当前线程的变量值相同时,说明还没线程修改该值,当前线程可以进行修改,也就是执行CAS操作,但如果期望值与当前线程不符,则说明该值已被其他线程修改,此时不执行更新操作,但可以选择重新读取该变量再尝试再次修改该变量,也可以放弃操作,原理图如下
8 |
9 | 
10 |
11 |
12 | > 由于CAS操作属于乐观派,它总认为自己可以成功完成操作,当多个线程同时使用CAS操作一个变量时,只有一个会胜出,并成功更新,其余均会失败,但失败的线程并不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作,这点从图中也可以看出来。基于这样的原理,CAS操作即使没有锁,同样知道其他线程对共享资源操作影响,并执行相应的处理措施。同时从这点也可以看出,由于无锁操作中没有锁的存在,因此不可能出现死锁的情况,也就是说无锁操作天生免疫死锁。
13 |
14 | # 如何实现
15 |
16 | > java中由UnSafe类实现,关于UnSafe的介绍放在了同级目录下。
17 |
18 |
--------------------------------------------------------------------------------
/jdk/thread/Exchanger.md:
--------------------------------------------------------------------------------
1 |
2 | ---------------------
3 | 作者:octopusflying
4 | 来源:CSDN
5 | 原文:https://blog.csdn.net/octopusflying/article/details/80634864
6 | 版权声明:本文为博主原创文章,转载请附上博文链接!
7 |
8 | 摘要: 原创出处 http://cmsblogs.com/?p=2269 「小明哥」欢迎转载,保留摘要,谢谢!
9 | # 概述
10 |
11 | > java.util.concurrent包中的Exchanger类可用于两个线程之间交换信息。可简单地将Exchanger对象理解为一个包含两个格子的容器,通过exchanger方法可以向两个格子中填充信息。当两个格子中的均被填充时,该对象会自动将两个格子的信息交换,然后返回给线程,从而实现两个线程的信息交换。
12 | 另外需要注意的是,Exchanger类仅可用作两个线程的信息交换,当超过两个线程调用同一个exchanger对象时,得到的结果是随机的,exchanger对象仅关心其包含的两个“格子”是否已被填充数据,当两个格子都填充数据完成时,该对象就认为线程之间已经配对成功,然后开始执行数据交换操作。
13 |
14 |
15 | # 示例代码
16 |
17 | ```java
18 | package com.bobo.basic.thread;
19 |
20 |
21 | import java.util.concurrent.Exchanger;
22 | import java.util.concurrent.Semaphore;
23 |
24 |
25 | class ExchangerTest extends Thread {
26 | private Exchanger exchanger;
27 | private String string;
28 | private String threadName;
29 |
30 | public ExchangerTest(Exchanger exchanger, String string,
31 | String threadName) {
32 | this.exchanger = exchanger;
33 | this.string = string;
34 | this.threadName = threadName;
35 | }
36 |
37 | @Override
38 | public void run() {
39 | try {
40 | System.out.println(threadName + ": " + exchanger.exchange(string));
41 | } catch (InterruptedException e) {
42 | // TODO Auto-generated catch block
43 | e.printStackTrace();
44 | }
45 | }
46 | }
47 |
48 | public class Test {
49 | public static void main(String[] args) {
50 | Exchanger exchanger = new Exchanger<>();
51 | ExchangerTest test1 = new ExchangerTest(exchanger, "string1",
52 | "thread-1");
53 | ExchangerTest test2 = new ExchangerTest(exchanger, "string2",
54 | "thread-2");
55 |
56 | test1.start();
57 | test2.start();
58 | }
59 | }
60 | ```
61 | >额,原理我就不写了,表示我太菜,有很多地方都看不懂。
--------------------------------------------------------------------------------
/jdk/thread/ThreadLocal源码分析.md:
--------------------------------------------------------------------------------
1 |
2 | ### 源码详解
3 |
4 | >这里针对的是set和get方法
5 |
6 | ### set方法
7 | ```java
8 |
9 | ThreadLocal