├── doc ├── notes │ ├── work(工作) │ │ ├── vpn.md │ │ ├── scala i18坑.md │ │ ├── release 环境remote debug.md │ │ ├── qs 查询重试策略.md │ │ ├── k8s-pod.md │ │ ├── QLB.md │ │ ├── AES 限制长度.md │ │ ├── sonar.md │ │ └── docker skywalking.md │ ├── linux │ │ ├── tmux.md │ │ ├── git.md │ │ ├── 命令.md │ │ └── docker.md │ ├── .DS_Store │ ├── os(操作系统) │ │ └── assembly.md │ ├── python │ │ ├── scrapy-api.md │ │ ├── 虚拟环境.md │ │ └── 安装python3.md │ ├── database(数据库) │ │ ├── dead.png │ │ ├── lock.png │ │ ├── muti.png │ │ ├── .DS_Store │ │ ├── btree.png │ │ ├── mysql │ │ │ ├── mysql远程数据库 查询连接速度过于慢.md │ │ │ ├── mysqlLock.md │ │ │ └── index.md │ │ └── redis │ │ │ └── redis.md │ ├── middware(中间件) │ │ ├── rabbitMq.md │ │ ├── kafka.md │ │ └── limiterRater.md │ ├── java │ │ ├── 笔经 │ │ │ └── 360 笔试.md │ │ ├── 面经 │ │ │ ├── 蘑菇街一面.md │ │ │ ├── 蚂蚁金服网商银行二面.md │ │ │ ├── 腾讯一面.md │ │ │ ├── Kyligence实习.md │ │ │ ├── 支付宝风控部门一面.md │ │ │ ├── 头条二面.md │ │ │ ├── 蚂蚁金服网商银行一面.md │ │ │ ├── 支付宝一面.md │ │ │ ├── 头条一面.md │ │ │ └── 腾讯二面.md │ │ ├── idea.md │ │ ├── JavaIO.md │ │ ├── JavaCollection.md │ │ ├── Quartz重复调度(任务重复执行)的问题排查.md │ │ ├── classLoader.md │ │ └── JavaConcurrent.md │ ├── todo │ │ └── need to learn.md │ ├── goal(目标规划) │ │ ├── 9月28 日到10月11日规划.md │ │ ├── 2019年度总结.md │ │ ├── 2018年度总结.md │ │ └── 7-3到7-4号规划.md │ ├── fp(函数式编程) │ │ ├── fp in scala.md │ │ ├── 如何学习函数式编程与Scala.md │ │ └── fp.md │ ├── tomcat │ │ ├── IO模型.md │ │ ├── 折腾不止 手写Java Http server.md │ │ └── Tomcat 源码解析 (3) - 容器.md │ ├── algorithm(算法) │ │ ├── DP 区间问题.md │ │ ├── tree.md │ │ ├── 剑值offer 刷题集合 │ │ │ ├── 回溯.md │ │ │ └── 二叉树.md │ │ ├── 图.md │ │ ├── 位运算.md │ │ ├── 貪心.md │ │ ├── 算法.md │ │ ├── leetCode TODO.md │ │ ├── 栈、队列、堆.md │ │ └── 链表.md │ ├── scala │ │ ├── 常用命令.md │ │ ├── learn scala.md │ │ └── akka 源码.md │ ├── bigdata(大数据) │ │ └── BloomFilter.md │ ├── network(计算机网络) │ │ ├── internet.md │ │ └── 网络概论笔记.md │ └── translate(翻译作品) │ │ ├── equals() 和 hashCode() 方法在Java中的关系.md │ │ └── sdk.md ├── .DS_Store └── images │ ├── webp │ ├── vo.png │ ├── aaa.png │ ├── images.png │ ├── upcasting.png │ ├── 164e8a5a634e71b4 │ ├── 169bde35523d0ae5 │ ├── 169bde35552fb49c │ ├── 169bde3556310c02 │ ├── 169bde3557ef6578 │ ├── 169bde356084eb69 │ ├── 169bf19851d3dce6 │ ├── 169bf198524e1b34 │ ├── 030931301899477.png │ ├── 1559221874187.png │ ├── 1559222070250.png │ ├── 1559222973516.png │ ├── 1559223152389.png │ ├── 1559223329448.png │ ├── 1559224720528.png │ ├── 1559226186513.png │ ├── 1559226409029.png │ ├── 1559282483503.png │ ├── 1559283754130.png │ ├── 1559284348326.png │ ├── 1559284348696.png │ ├── 1559285593459.png │ ├── 1559285941998.png │ ├── 1559287173000.png │ ├── 1559307942030.png │ ├── 1559310072992.png │ ├── 1559741999036.png │ ├── 1559742028636.png │ ├── 1559742033662.png │ ├── 1559742437450.png │ ├── 1559742541710.png │ ├── 1559835354626.png │ ├── 1559887343136.png │ ├── 1559889450257.png │ ├── 1559890548807.png │ ├── 1559891328836.png │ ├── 1559893595269.png │ ├── 1559923736699.png │ ├── 1559923977411.png │ ├── 1559926862813.png │ ├── 1560013730504.png │ ├── 1560352046903.png │ ├── 1560431969894.png │ ├── 1561184422791.png │ ├── 1561187280868.png │ ├── 1561188316395.png │ ├── 1561188672137.png │ ├── 1561214190446.png │ ├── 1561214260291.png │ ├── 1561280721416.png │ ├── 1561292440233.png │ ├── 1561293307834.png │ ├── 1561732381044.png │ ├── 1561732644394.png │ ├── 1561733106554.png │ ├── 1561733457273.png │ ├── 1561734420390.png │ ├── 1561817039671.png │ ├── 1561882183969.png │ ├── 1562077236014.png │ ├── 1562077664444.png │ ├── 1562078271743.png │ ├── 1562398604770.png │ ├── 1562553013374.png │ ├── 1562554322901.png │ ├── 1562554585495.png │ ├── 1562554803379.png │ ├── 1562575957668.png │ ├── 1562682918033.png │ ├── 1562822700914.png │ ├── 1562823044829.png │ ├── 1562823527614.png │ ├── 1562844211568.png │ ├── 1562855661632.png │ ├── 1562899163601.png │ ├── 1562899230830.png │ ├── 1562900579891.png │ ├── 1562932004995.png │ ├── 1562932437042.png │ ├── 1562932992998.png │ ├── 1563007998170.png │ ├── 1563008406804.png │ ├── 1563091010474.png │ ├── 1564464550962.png │ ├── 1564464572147.png │ ├── 1564670779560.png │ ├── 1564904495635.png │ ├── 1564905737225.png │ ├── 1564905750262.png │ ├── 1565518391960.png │ ├── 1565613365296.png │ ├── 1565613534148.png │ ├── 1565613764987.png │ ├── 1565613821427.png │ ├── 1565613896473.png │ ├── 1565614271546.png │ ├── 1565616025008.png │ ├── 1565616052121.png │ ├── 1565616247238.png │ ├── 1565616348312.png │ ├── 1565617807857.png │ ├── 1565618081029.png │ ├── 1565618180009.png │ ├── 1565618253207.png │ ├── 1565618412458.png │ ├── 1565619272559.png │ ├── 1565703106108.png │ ├── 1565708534295.png │ ├── 1565712724516.png │ ├── 1565878391797.png │ ├── 1565878396072.png │ ├── 1565882162407.png │ ├── 1566305710536.png │ ├── 1566311031528.png │ ├── 1566311048424.png │ ├── 1566395436962.png │ ├── 1566441210389.png │ ├── 1567236630493.png │ ├── 1567236837919.png │ ├── 1569566077883.png │ ├── 1569671010390.png │ ├── 1569671454613.png │ ├── 1569674676555.png │ ├── 111938_nBce_222173.png │ ├── avl_right_rotation.jpg │ ├── webp-20190919153951707 │ ├── webp-20190919154014135 │ ├── 8394323_1307440587b6WG.jpg │ ├── 1234352-2738b3eb14207b1c.webp │ ├── 1234352-e9c36c1963b96e3b.webp │ ├── 191918-81271b7d3443a160.webp │ ├── 20190507171801023_GIMCAP.jpg │ ├── 20190507171801166_XSAERU.jpg │ ├── 20190507171801286_FKKWCB.jpg │ ├── 20190507171801394_DJPDIH.jpg │ ├── 20190507171801597_FYMMZS.jpg │ ├── 20190507171801695_INENKV.jpg │ ├── 20190507171801780_BKSEQA.jpg │ ├── 20190507171801907_JCCWBG.jpg │ ├── Sun, 26 May 2019 235539.jpeg │ ├── Sun, 26 May 2019 235747.jpeg │ ├── 1559222070250-1559305284967.png │ ├── 1559222070250-1565618604591.png │ ├── 1559222973516-1559305285290.png │ ├── 1559223152389-1559305286008.png │ ├── 1559223329448-1559305285606.png │ ├── 1559224720528-1559305286008.png │ ├── 1559224720528-1565619704251.png │ ├── 1559226186513-1559305286557.png │ ├── 1559226409029-1559305286349.png │ ├── 1559282483503-1559305286941.png │ ├── 1559283754130-1559305287293.png │ ├── 1561882183969-1561883475753.png │ ├── 1564904495635-1564910064504.png │ ├── 169bf19851d3dce6-1562739070773 │ ├── 030931301899477-1559111854402.png │ ├── b17448d868e81c5a53c419a70d3fe59e │ ├── d8bf92c7906718271fdb8b0d2d5fe5b4 │ ├── 81282f8c4d26fcf5375392a2a856a4bc.png │ ├── 1910205370-5b441c7329be1_articlex.png │ ├── 345531-20160330111438473-1015724073.png │ ├── 431521-20160523163606881-813374140.png │ ├── 738818-20181211000636874-1536263943.jpg │ ├── 738818-20181211000636874-1536263943.png │ ├── 1234352-2738b3eb14207b1c-1559305287374.webp │ ├── 1234352-e9c36c1963b96e3b-1559305287176.webp │ ├── 030931301899477-1559111854402-1559111856420.png │ ├── 4107856_1568009455024_C5529731D205FF0536BFD79DC2B77E2F.png │ ├── 4107856_1568009458775_8644D040AB160A2A01503A66EF51DC85.png │ ├── 4107856_1568009463299_2CDA94D4E23904213327085490B646D8.png │ ├── 4107856_1568009467459_74589865AF0C2B502DE066090FDB7282.png │ └── 4107856_1568009472158_1E574037FC5D7EA7D4FBBDBE3C4D392E.png ├── .DS_Store ├── script ├── .DS_Store ├── b.sh └── c.sh ├── README.en-US.md └── README.md /doc/notes/work(工作)/vpn.md: -------------------------------------------------------------------------------- 1 | 当前配置 2 | 3 | VPN 不走全局流量 4 | 5 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/.DS_Store -------------------------------------------------------------------------------- /doc/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/.DS_Store -------------------------------------------------------------------------------- /doc/images/webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/webp -------------------------------------------------------------------------------- /doc/notes/linux/tmux.md: -------------------------------------------------------------------------------- 1 | - `Ctrl+b %`:划分左右两个窗格。 2 | 3 | - `Ctrl+b "`:划分上下两个窗格。 4 | 5 | -------------------------------------------------------------------------------- /doc/images/vo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/vo.png -------------------------------------------------------------------------------- /script/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/script/.DS_Store -------------------------------------------------------------------------------- /doc/images/aaa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/aaa.png -------------------------------------------------------------------------------- /doc/notes/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/notes/.DS_Store -------------------------------------------------------------------------------- /doc/notes/os(操作系统)/assembly.md: -------------------------------------------------------------------------------- 1 | # 基础知识 2 | 3 | ## 汇编语言的组成 4 | 5 | * 汇编指令 6 | * 伪指令 7 | * 其他符号 8 | 9 | -------------------------------------------------------------------------------- /doc/images/images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/images.png -------------------------------------------------------------------------------- /doc/images/upcasting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/upcasting.png -------------------------------------------------------------------------------- /doc/notes/python/scrapy-api.md: -------------------------------------------------------------------------------- 1 | 开启scrapyd的服务 2 | `scrapyd` 3 | 4 | 查看项目中的scrapy 5 | `scrapy list` 6 | 7 | -------------------------------------------------------------------------------- /doc/images/164e8a5a634e71b4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/164e8a5a634e71b4 -------------------------------------------------------------------------------- /doc/images/169bde35523d0ae5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/169bde35523d0ae5 -------------------------------------------------------------------------------- /doc/images/169bde35552fb49c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/169bde35552fb49c -------------------------------------------------------------------------------- /doc/images/169bde3556310c02: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/169bde3556310c02 -------------------------------------------------------------------------------- /doc/images/169bde3557ef6578: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/169bde3557ef6578 -------------------------------------------------------------------------------- /doc/images/169bde356084eb69: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/169bde356084eb69 -------------------------------------------------------------------------------- /doc/images/169bf19851d3dce6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/169bf19851d3dce6 -------------------------------------------------------------------------------- /doc/images/169bf198524e1b34: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/169bf198524e1b34 -------------------------------------------------------------------------------- /doc/images/030931301899477.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/030931301899477.png -------------------------------------------------------------------------------- /doc/images/1559221874187.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559221874187.png -------------------------------------------------------------------------------- /doc/images/1559222070250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559222070250.png -------------------------------------------------------------------------------- /doc/images/1559222973516.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559222973516.png -------------------------------------------------------------------------------- /doc/images/1559223152389.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559223152389.png -------------------------------------------------------------------------------- /doc/images/1559223329448.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559223329448.png -------------------------------------------------------------------------------- /doc/images/1559224720528.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559224720528.png -------------------------------------------------------------------------------- /doc/images/1559226186513.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559226186513.png -------------------------------------------------------------------------------- /doc/images/1559226409029.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559226409029.png -------------------------------------------------------------------------------- /doc/images/1559282483503.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559282483503.png -------------------------------------------------------------------------------- /doc/images/1559283754130.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559283754130.png -------------------------------------------------------------------------------- /doc/images/1559284348326.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559284348326.png -------------------------------------------------------------------------------- /doc/images/1559284348696.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559284348696.png -------------------------------------------------------------------------------- /doc/images/1559285593459.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559285593459.png -------------------------------------------------------------------------------- /doc/images/1559285941998.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559285941998.png -------------------------------------------------------------------------------- /doc/images/1559287173000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559287173000.png -------------------------------------------------------------------------------- /doc/images/1559307942030.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559307942030.png -------------------------------------------------------------------------------- /doc/images/1559310072992.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559310072992.png -------------------------------------------------------------------------------- /doc/images/1559741999036.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559741999036.png -------------------------------------------------------------------------------- /doc/images/1559742028636.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559742028636.png -------------------------------------------------------------------------------- /doc/images/1559742033662.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559742033662.png -------------------------------------------------------------------------------- /doc/images/1559742437450.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559742437450.png -------------------------------------------------------------------------------- /doc/images/1559742541710.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559742541710.png -------------------------------------------------------------------------------- /doc/images/1559835354626.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559835354626.png -------------------------------------------------------------------------------- /doc/images/1559887343136.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559887343136.png -------------------------------------------------------------------------------- /doc/images/1559889450257.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559889450257.png -------------------------------------------------------------------------------- /doc/images/1559890548807.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559890548807.png -------------------------------------------------------------------------------- /doc/images/1559891328836.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559891328836.png -------------------------------------------------------------------------------- /doc/images/1559893595269.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559893595269.png -------------------------------------------------------------------------------- /doc/images/1559923736699.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559923736699.png -------------------------------------------------------------------------------- /doc/images/1559923977411.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559923977411.png -------------------------------------------------------------------------------- /doc/images/1559926862813.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559926862813.png -------------------------------------------------------------------------------- /doc/images/1560013730504.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1560013730504.png -------------------------------------------------------------------------------- /doc/images/1560352046903.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1560352046903.png -------------------------------------------------------------------------------- /doc/images/1560431969894.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1560431969894.png -------------------------------------------------------------------------------- /doc/images/1561184422791.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561184422791.png -------------------------------------------------------------------------------- /doc/images/1561187280868.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561187280868.png -------------------------------------------------------------------------------- /doc/images/1561188316395.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561188316395.png -------------------------------------------------------------------------------- /doc/images/1561188672137.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561188672137.png -------------------------------------------------------------------------------- /doc/images/1561214190446.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561214190446.png -------------------------------------------------------------------------------- /doc/images/1561214260291.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561214260291.png -------------------------------------------------------------------------------- /doc/images/1561280721416.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561280721416.png -------------------------------------------------------------------------------- /doc/images/1561292440233.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561292440233.png -------------------------------------------------------------------------------- /doc/images/1561293307834.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561293307834.png -------------------------------------------------------------------------------- /doc/images/1561732381044.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561732381044.png -------------------------------------------------------------------------------- /doc/images/1561732644394.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561732644394.png -------------------------------------------------------------------------------- /doc/images/1561733106554.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561733106554.png -------------------------------------------------------------------------------- /doc/images/1561733457273.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561733457273.png -------------------------------------------------------------------------------- /doc/images/1561734420390.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561734420390.png -------------------------------------------------------------------------------- /doc/images/1561817039671.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561817039671.png -------------------------------------------------------------------------------- /doc/images/1561882183969.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561882183969.png -------------------------------------------------------------------------------- /doc/images/1562077236014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562077236014.png -------------------------------------------------------------------------------- /doc/images/1562077664444.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562077664444.png -------------------------------------------------------------------------------- /doc/images/1562078271743.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562078271743.png -------------------------------------------------------------------------------- /doc/images/1562398604770.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562398604770.png -------------------------------------------------------------------------------- /doc/images/1562553013374.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562553013374.png -------------------------------------------------------------------------------- /doc/images/1562554322901.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562554322901.png -------------------------------------------------------------------------------- /doc/images/1562554585495.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562554585495.png -------------------------------------------------------------------------------- /doc/images/1562554803379.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562554803379.png -------------------------------------------------------------------------------- /doc/images/1562575957668.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562575957668.png -------------------------------------------------------------------------------- /doc/images/1562682918033.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562682918033.png -------------------------------------------------------------------------------- /doc/images/1562822700914.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562822700914.png -------------------------------------------------------------------------------- /doc/images/1562823044829.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562823044829.png -------------------------------------------------------------------------------- /doc/images/1562823527614.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562823527614.png -------------------------------------------------------------------------------- /doc/images/1562844211568.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562844211568.png -------------------------------------------------------------------------------- /doc/images/1562855661632.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562855661632.png -------------------------------------------------------------------------------- /doc/images/1562899163601.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562899163601.png -------------------------------------------------------------------------------- /doc/images/1562899230830.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562899230830.png -------------------------------------------------------------------------------- /doc/images/1562900579891.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562900579891.png -------------------------------------------------------------------------------- /doc/images/1562932004995.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562932004995.png -------------------------------------------------------------------------------- /doc/images/1562932437042.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562932437042.png -------------------------------------------------------------------------------- /doc/images/1562932992998.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1562932992998.png -------------------------------------------------------------------------------- /doc/images/1563007998170.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1563007998170.png -------------------------------------------------------------------------------- /doc/images/1563008406804.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1563008406804.png -------------------------------------------------------------------------------- /doc/images/1563091010474.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1563091010474.png -------------------------------------------------------------------------------- /doc/images/1564464550962.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1564464550962.png -------------------------------------------------------------------------------- /doc/images/1564464572147.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1564464572147.png -------------------------------------------------------------------------------- /doc/images/1564670779560.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1564670779560.png -------------------------------------------------------------------------------- /doc/images/1564904495635.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1564904495635.png -------------------------------------------------------------------------------- /doc/images/1564905737225.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1564905737225.png -------------------------------------------------------------------------------- /doc/images/1564905750262.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1564905750262.png -------------------------------------------------------------------------------- /doc/images/1565518391960.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565518391960.png -------------------------------------------------------------------------------- /doc/images/1565613365296.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565613365296.png -------------------------------------------------------------------------------- /doc/images/1565613534148.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565613534148.png -------------------------------------------------------------------------------- /doc/images/1565613764987.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565613764987.png -------------------------------------------------------------------------------- /doc/images/1565613821427.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565613821427.png -------------------------------------------------------------------------------- /doc/images/1565613896473.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565613896473.png -------------------------------------------------------------------------------- /doc/images/1565614271546.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565614271546.png -------------------------------------------------------------------------------- /doc/images/1565616025008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565616025008.png -------------------------------------------------------------------------------- /doc/images/1565616052121.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565616052121.png -------------------------------------------------------------------------------- /doc/images/1565616247238.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565616247238.png -------------------------------------------------------------------------------- /doc/images/1565616348312.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565616348312.png -------------------------------------------------------------------------------- /doc/images/1565617807857.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565617807857.png -------------------------------------------------------------------------------- /doc/images/1565618081029.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565618081029.png -------------------------------------------------------------------------------- /doc/images/1565618180009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565618180009.png -------------------------------------------------------------------------------- /doc/images/1565618253207.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565618253207.png -------------------------------------------------------------------------------- /doc/images/1565618412458.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565618412458.png -------------------------------------------------------------------------------- /doc/images/1565619272559.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565619272559.png -------------------------------------------------------------------------------- /doc/images/1565703106108.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565703106108.png -------------------------------------------------------------------------------- /doc/images/1565708534295.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565708534295.png -------------------------------------------------------------------------------- /doc/images/1565712724516.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565712724516.png -------------------------------------------------------------------------------- /doc/images/1565878391797.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565878391797.png -------------------------------------------------------------------------------- /doc/images/1565878396072.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565878396072.png -------------------------------------------------------------------------------- /doc/images/1565882162407.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1565882162407.png -------------------------------------------------------------------------------- /doc/images/1566305710536.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1566305710536.png -------------------------------------------------------------------------------- /doc/images/1566311031528.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1566311031528.png -------------------------------------------------------------------------------- /doc/images/1566311048424.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1566311048424.png -------------------------------------------------------------------------------- /doc/images/1566395436962.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1566395436962.png -------------------------------------------------------------------------------- /doc/images/1566441210389.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1566441210389.png -------------------------------------------------------------------------------- /doc/images/1567236630493.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1567236630493.png -------------------------------------------------------------------------------- /doc/images/1567236837919.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1567236837919.png -------------------------------------------------------------------------------- /doc/images/1569566077883.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1569566077883.png -------------------------------------------------------------------------------- /doc/images/1569671010390.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1569671010390.png -------------------------------------------------------------------------------- /doc/images/1569671454613.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1569671454613.png -------------------------------------------------------------------------------- /doc/images/1569674676555.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1569674676555.png -------------------------------------------------------------------------------- /doc/notes/database(数据库)/dead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/notes/database(数据库)/dead.png -------------------------------------------------------------------------------- /doc/notes/database(数据库)/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/notes/database(数据库)/lock.png -------------------------------------------------------------------------------- /doc/notes/database(数据库)/muti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/notes/database(数据库)/muti.png -------------------------------------------------------------------------------- /doc/notes/middware(中间件)/rabbitMq.md: -------------------------------------------------------------------------------- 1 | rabbitmq-server用来启动RabbitMQ服务器进程: 2 | 3 | > \# rabbitmq-server -detached 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /doc/images/111938_nBce_222173.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/111938_nBce_222173.png -------------------------------------------------------------------------------- /doc/images/avl_right_rotation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/avl_right_rotation.jpg -------------------------------------------------------------------------------- /doc/images/webp-20190919153951707: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/webp-20190919153951707 -------------------------------------------------------------------------------- /doc/images/webp-20190919154014135: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/webp-20190919154014135 -------------------------------------------------------------------------------- /doc/notes/database(数据库)/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/notes/database(数据库)/.DS_Store -------------------------------------------------------------------------------- /doc/notes/database(数据库)/btree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/notes/database(数据库)/btree.png -------------------------------------------------------------------------------- /doc/images/8394323_1307440587b6WG.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/8394323_1307440587b6WG.jpg -------------------------------------------------------------------------------- /doc/images/1234352-2738b3eb14207b1c.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1234352-2738b3eb14207b1c.webp -------------------------------------------------------------------------------- /doc/images/1234352-e9c36c1963b96e3b.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1234352-e9c36c1963b96e3b.webp -------------------------------------------------------------------------------- /doc/images/191918-81271b7d3443a160.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/191918-81271b7d3443a160.webp -------------------------------------------------------------------------------- /doc/images/20190507171801023_GIMCAP.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/20190507171801023_GIMCAP.jpg -------------------------------------------------------------------------------- /doc/images/20190507171801166_XSAERU.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/20190507171801166_XSAERU.jpg -------------------------------------------------------------------------------- /doc/images/20190507171801286_FKKWCB.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/20190507171801286_FKKWCB.jpg -------------------------------------------------------------------------------- /doc/images/20190507171801394_DJPDIH.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/20190507171801394_DJPDIH.jpg -------------------------------------------------------------------------------- /doc/images/20190507171801597_FYMMZS.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/20190507171801597_FYMMZS.jpg -------------------------------------------------------------------------------- /doc/images/20190507171801695_INENKV.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/20190507171801695_INENKV.jpg -------------------------------------------------------------------------------- /doc/images/20190507171801780_BKSEQA.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/20190507171801780_BKSEQA.jpg -------------------------------------------------------------------------------- /doc/images/20190507171801907_JCCWBG.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/20190507171801907_JCCWBG.jpg -------------------------------------------------------------------------------- /doc/images/Sun, 26 May 2019 235539.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/Sun, 26 May 2019 235539.jpeg -------------------------------------------------------------------------------- /doc/images/Sun, 26 May 2019 235747.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/Sun, 26 May 2019 235747.jpeg -------------------------------------------------------------------------------- /doc/notes/java/笔经/360 笔试.md: -------------------------------------------------------------------------------- 1 | ![1565878391797](../../../images/1565878391797.png) 2 | 3 | ![1565878396072](../../../images/1565878396072.png) -------------------------------------------------------------------------------- /doc/images/1559222070250-1559305284967.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559222070250-1559305284967.png -------------------------------------------------------------------------------- /doc/images/1559222070250-1565618604591.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559222070250-1565618604591.png -------------------------------------------------------------------------------- /doc/images/1559222973516-1559305285290.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559222973516-1559305285290.png -------------------------------------------------------------------------------- /doc/images/1559223152389-1559305286008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559223152389-1559305286008.png -------------------------------------------------------------------------------- /doc/images/1559223329448-1559305285606.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559223329448-1559305285606.png -------------------------------------------------------------------------------- /doc/images/1559224720528-1559305286008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559224720528-1559305286008.png -------------------------------------------------------------------------------- /doc/images/1559224720528-1565619704251.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559224720528-1565619704251.png -------------------------------------------------------------------------------- /doc/images/1559226186513-1559305286557.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559226186513-1559305286557.png -------------------------------------------------------------------------------- /doc/images/1559226409029-1559305286349.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559226409029-1559305286349.png -------------------------------------------------------------------------------- /doc/images/1559282483503-1559305286941.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559282483503-1559305286941.png -------------------------------------------------------------------------------- /doc/images/1559283754130-1559305287293.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1559283754130-1559305287293.png -------------------------------------------------------------------------------- /doc/images/1561882183969-1561883475753.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1561882183969-1561883475753.png -------------------------------------------------------------------------------- /doc/images/1564904495635-1564910064504.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1564904495635-1564910064504.png -------------------------------------------------------------------------------- /doc/images/169bf19851d3dce6-1562739070773: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/169bf19851d3dce6-1562739070773 -------------------------------------------------------------------------------- /doc/images/030931301899477-1559111854402.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/030931301899477-1559111854402.png -------------------------------------------------------------------------------- /doc/images/b17448d868e81c5a53c419a70d3fe59e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/b17448d868e81c5a53c419a70d3fe59e -------------------------------------------------------------------------------- /doc/images/d8bf92c7906718271fdb8b0d2d5fe5b4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/d8bf92c7906718271fdb8b0d2d5fe5b4 -------------------------------------------------------------------------------- /doc/images/81282f8c4d26fcf5375392a2a856a4bc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/81282f8c4d26fcf5375392a2a856a4bc.png -------------------------------------------------------------------------------- /doc/images/1910205370-5b441c7329be1_articlex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1910205370-5b441c7329be1_articlex.png -------------------------------------------------------------------------------- /doc/images/345531-20160330111438473-1015724073.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/345531-20160330111438473-1015724073.png -------------------------------------------------------------------------------- /doc/images/431521-20160523163606881-813374140.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/431521-20160523163606881-813374140.png -------------------------------------------------------------------------------- /doc/images/738818-20181211000636874-1536263943.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/738818-20181211000636874-1536263943.jpg -------------------------------------------------------------------------------- /doc/images/738818-20181211000636874-1536263943.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/738818-20181211000636874-1536263943.png -------------------------------------------------------------------------------- /doc/notes/java/面经/蘑菇街一面.md: -------------------------------------------------------------------------------- 1 | 负载均衡 DR 2 | 3 | HashMap 4 | 5 | GC 6 | 7 | ping 6w 台虚机怎么做 8 | 9 | TCP 定时器 10 | 11 | 拥塞控制 12 | 13 | 管道种类 14 | 15 | -------------------------------------------------------------------------------- /doc/notes/todo/need to learn.md: -------------------------------------------------------------------------------- 1 | * kafka 基本知识 2 | 3 | * kafka 保证幂等性 4 | 5 | * 微服务到底是什么 6 | 7 | * Google protobuf 8 | 9 | * ForkJoinTask 10 | 11 | -------------------------------------------------------------------------------- /doc/images/1234352-2738b3eb14207b1c-1559305287374.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1234352-2738b3eb14207b1c-1559305287374.webp -------------------------------------------------------------------------------- /doc/images/1234352-e9c36c1963b96e3b-1559305287176.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/1234352-e9c36c1963b96e3b-1559305287176.webp -------------------------------------------------------------------------------- /doc/images/030931301899477-1559111854402-1559111856420.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/030931301899477-1559111854402-1559111856420.png -------------------------------------------------------------------------------- /doc/notes/java/面经/蚂蚁金服网商银行二面.md: -------------------------------------------------------------------------------- 1 | Java的内存回收机制 2 | 3 | 用户态和内核态 4 | 5 | 喜欢linux的哪一点 6 | 7 | linux的内存管理是怎么做的 8 | 9 | Java的面向对象思想 10 | 11 | 用java写过那些项目? 12 | 13 | -------------------------------------------------------------------------------- /script/b.sh: -------------------------------------------------------------------------------- 1 | cd /e/Project/Java-BackEnd-Notes 2 | # 自动获取远端分支 3 | git pull origin master 4 | git add . 5 | result=`git status -s` 6 | git commit -m "$result" 7 | git push origin master 8 | -------------------------------------------------------------------------------- /script/c.sh: -------------------------------------------------------------------------------- 1 | cd /d/project/Java-BackEnd-Notes 2 | # 自动获取远端分支 3 | git pull origin master 4 | git add . 5 | result=`git status -s` 6 | git commit -m "$result" 7 | git push origin master 8 | 9 | -------------------------------------------------------------------------------- /doc/images/4107856_1568009455024_C5529731D205FF0536BFD79DC2B77E2F.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/4107856_1568009455024_C5529731D205FF0536BFD79DC2B77E2F.png -------------------------------------------------------------------------------- /doc/images/4107856_1568009458775_8644D040AB160A2A01503A66EF51DC85.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/4107856_1568009458775_8644D040AB160A2A01503A66EF51DC85.png -------------------------------------------------------------------------------- /doc/images/4107856_1568009463299_2CDA94D4E23904213327085490B646D8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/4107856_1568009463299_2CDA94D4E23904213327085490B646D8.png -------------------------------------------------------------------------------- /doc/images/4107856_1568009467459_74589865AF0C2B502DE066090FDB7282.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/4107856_1568009467459_74589865AF0C2B502DE066090FDB7282.png -------------------------------------------------------------------------------- /doc/images/4107856_1568009472158_1E574037FC5D7EA7D4FBBDBE3C4D392E.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiantang/Java-BackEnd-Notes/HEAD/doc/images/4107856_1568009472158_1E574037FC5D7EA7D4FBBDBE3C4D392E.png -------------------------------------------------------------------------------- /doc/notes/work(工作)/scala i18坑.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## i18n 无法加入编译 4 | 5 | Can't find bundle for base name filename.properties, locale ch_CN 6 | 7 | 真的坑 8 | 9 | 是因为编译没把资源文件编译进去 10 | 11 | 复制resource里面 注意是里面!!!! 的文件到 target/scala-2.12 文件夹下面 -------------------------------------------------------------------------------- /doc/notes/python/虚拟环境.md: -------------------------------------------------------------------------------- 1 | 激活虚拟环境。 2 | `source venv/bin/activate` 3 | 4 | 开启python项目 5 | `sudo python3 manage.py runserver 0.0.0.0:80` 6 | 7 | 后台运行任务 8 | 9 | 暂停 10 | `ctrl+z` 11 | 12 | 将程序在后台运行 13 | `bg %1` 14 | 15 | 取消控制 16 | `disown` 17 | 18 | 退出虚拟环境 19 | `deactivate` 20 | 21 | -------------------------------------------------------------------------------- /doc/notes/work(工作)/release 环境remote debug.md: -------------------------------------------------------------------------------- 1 | ```shell 2 | JAVA_OPTIONS="-server -XX:+UseG1GC -Xmx512M -XX:MaxDirectMemorySize=128M" 3 | ``` 4 | 5 | => 6 | 7 | ```shell 8 | JAVA_OPTIONS="-server -XX:+UseG1GC -Xmx512M -XX:MaxDirectMemorySize=128M -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005" 9 | ``` 10 | 11 | -------------------------------------------------------------------------------- /doc/notes/goal(目标规划)/9月28 日到10月11日规划.md: -------------------------------------------------------------------------------- 1 | 10:00 ->11:00 阅读Tomcat 源码 跟着书写每天25页 **必须做总结** 2 | 3 | 13:30 -> 17:00 阅读源码结束 4 | 5 | 17:00 -> 20:00 休息恰饭 6 | 7 | 20:00 -> 22:00 做一下剑指offer 每日3题 到11日的时候至少54题 每做一道**必须更新题解** 8 | 9 | **每日必须更新完成的数目** 10 | 11 | 9月 28 日 8点回到寝室并且收拾东西 12 | 13 | 9月29日 因为要回家不算 14 | 15 | 16 | 17 | 18 | 19 | 9月28日 日报 20 | 21 | * 完成最近15天的短期Tomcat & 算法学习规划 22 | * 已完成对 类加载器章节的复习。 10 页 25/280 23 | * HTTP 45 / 280 今天看了 35 页 24 | -------------------------------------------------------------------------------- /doc/notes/fp(函数式编程)/fp in scala.md: -------------------------------------------------------------------------------- 1 | 什么是函数式编程? 2 | 3 | 函数式编程:只用纯函数来构造程序。 4 | 5 | 什么是纯函数? 6 | 7 | 没有副作用的函数。 8 | 9 | 什么是副作用? 10 | 11 | 一个带有副作用的函数,不仅会简单的返回一个值,而且会干一些其他的事情。 12 | 13 | 14 | 15 | 16 | 17 | 非严格求值 18 | 19 | 20 | 21 | ```scala 22 | def getOrElse[B >: A](default: => B): B = this match{ 23 | case None => default 24 | case Some(x) => x 25 | } 26 | ``` 27 | 28 | 可以看到如果为 None 的情况下计算 default 的值,否则返回内部的值 29 | 30 | 这样能提高性能 31 | 32 | -------------------------------------------------------------------------------- /doc/notes/goal(目标规划)/2019年度总结.md: -------------------------------------------------------------------------------- 1 | 又到年底了,再总结总结我的2019吧。 2 | 3 | 今天正好也是和失落情绪撕咬的一天。 4 | 5 | 这一年是我的大三秋招年,也就是需要找工作,为资本家工作的一年。 6 | 7 | 谈谈失去和获得吧。 8 | 9 | 10 | 11 | 分为三点讲吧,怕自己说不清楚事情。 12 | 13 | 14 | 15 | 先谈身体吧,其实上半年在学校的时候,有经常锻炼的习惯,但是一到下半年准备秋招的时候,索性锻炼都没去锻炼了。到现在身体越来越差,终于意识到,身体是最重要的东西,比任何东西都弥足珍贵,也许我必须在20年把锻炼身体放在第一位,而不是为了什么所谓的绩效,导致身体垮掉,因为身体健康能保证你之后的生命的持续输出,如果身体垮了,在病床上花的钱很快能将你的积蓄清空。 16 | 17 | 18 | 19 | 再谈技术,因为经历秋招,那写丧心病狂的面试题之后,基础更加牢固了。原来也打算以 Java 作为自己的第一语言,但是秋招进了一家以 scala 技术栈的公司 20 | 21 | // TODO xxx 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /doc/notes/java/面经/腾讯一面.md: -------------------------------------------------------------------------------- 1 | * 抽象类和接口有什么区别 2 | 3 | * 在接口里面怎么去实现一个数据的共享 4 | 5 | * 有用过注解嘛 (我这里简单的回答了一下,应该要扯到编译时和运行时 和元编程 6 | 7 | * spring boot 如何自动配置 8 | 9 | * Java 如何去创建一个JDBC连接 10 | 11 | * 判断变量,两个变量相等 == 和 equal的区别 12 | 13 | * HashMap 的工作原理 应该讲一下扩容机制的 14 | 15 | * 打开腾讯的首页,从你输入网址到时候呈现出来,整个过程会经过哪些环节。 16 | 17 | * HTTPS 非对称加密 18 | 19 | * 长连接和短连接的区别 20 | 21 | * 什么时候用长连接 什么时候用短链接 22 | 23 | * tcp怎么进行流量控制 24 | 25 | * linux 命令怎么去抓包一个端口 26 | 27 | * 用文件A 去替换一个目录下不同层次的文件B 28 | 29 | * 排序的几种方式 以及他们的区别 30 | 31 | * 希尔排序 快排 是如何排序的 时间复杂度 思路 32 | 33 | -------------------------------------------------------------------------------- /doc/notes/database(数据库)/mysql/mysql远程数据库 查询连接速度过于慢.md: -------------------------------------------------------------------------------- 1 | 如果是ubuntu 16 就修改 2 | 3 | `/etc/mysql/mysql.conf.d/mysqld.cnf` 4 | 在`[mysqld]`中添加` skip-name-resolve` 5 | 6 | ``` 7 | [mysqld] 8 | port = 3306 9 | socket = /tmp/mysql.sock 10 | skip-external-locking 11 | skip-name-resolve 12 | ``` 13 | 14 | 然后重启mysql服务器 15 | 16 | `sudo /etc/init.d/mysql start` 17 | 18 | 这个方法的弊端就是在mysql的授权表中不能使用主机名,只能使用ip 19 | 20 | 流程是这样的mysql接受到连接请求的时候,获取到了客户端的ip,为了更好的匹配这个授权记录,如果mysql服务器设置了dns服务器,但是客户端ip并没有dns上有响应的域名,就会很慢。 21 | 22 | `skip-name-resolve` 就是跳过了这个过程 -------------------------------------------------------------------------------- /doc/notes/work(工作)/qs 查询重试策略.md: -------------------------------------------------------------------------------- 1 | 方案: 2 | 3 | 1.对于查询 QueryActor 的失败查询,传入封装好的 GroupUsersRequest 内部包含对应的请求偏移量给 重试的Actor 4 | 5 | 2.通过模式匹配获得数组的第一个睡眠的时间长度,随后先执行睡眠操作,因为上一次的重试或者QueryActor 刚刚结束。 6 | 7 | 3.随后执行对应的请求操作,判断是否成功。 8 | 9 | 4.如果重试成功,记录当前重试的次数,与重试的总计用时,以及GroupUsersRequest 中的ai,查询的url ,写入retry_qs_invoke 表中,随后对成功的数据执行 QueryActor 相同的逻辑,对数据根据channel 分类随后建立 JobContext 交付给 checkpointTaskActor 处理,逻辑和 QueryActor 查询成功的逻辑类似。 10 | 5.A:如果重试失败,并且剩下的重试 List 为空,就记录重试的总计用时,以及GroupUsersRequest 中的 ai,查询的url ,写入 retry_qs_invoke 表中。B:如果重试失败,并且剩下的List不为空,就将剩下的List 与 GroupUsersRequest 11 | 传入 RetryActor 调用自己。 12 | 13 | -------------------------------------------------------------------------------- /doc/notes/work(工作)/k8s-pod.md: -------------------------------------------------------------------------------- 1 | Kubernetes对象模型中可部署的最小对象。 2 | 3 | ## 了解Pod 4 | 5 | Pod是Kubernetes创建或部署的最小/最简单的基本单位,一个Pod代表集群上正在运行的一个进程。 6 | 7 | 一个Pod封装一个应用容器(也可以有多个容器),存储资源、一个独立的网络IP以及管理控制容器运行方式的策略选项。Pod代表部署的一个单位:Kubernetes中单个应用的实例,它可能由单个容器或多个容器共享组成的资源。 8 | 9 | > Docker是Kubernetes Pod中最常见的runtime ,Pods也支持其他容器runtimes。 10 | 11 | Kubernetes中的Pod使用可分两种主要方式: 12 | 13 | - Pod中运行一个容器。“one-container-per-Pod”模式是Kubernetes最常见的用法; 在这种情况下,你可以将Pod视为单个封装的容器,但是Kubernetes是直接管理Pod而不是容器。 14 | - Pods中运行多个需要一起工作的容器。Pod可以封装紧密耦合的应用,它们需要由多个容器组成,它们之间能够共享资源,这些容器可以形成一个单一的内部service单位 - 一个容器共享文件,另一个“sidecar”容器来更新这些文件。Pod将这些容器的存储资源作为一个实体来管理。 -------------------------------------------------------------------------------- /doc/notes/python/安装python3.md: -------------------------------------------------------------------------------- 1 | 创建文件 2 | `mkdir /usr/local/python3` 3 | 4 | 下载源码 5 | `wget https://www.python.org/ftp/python/3.6.3/Python-3.6.3.tgz` 6 | 7 | 解压 8 | `tar -xvf Python-3.6.3.tgz` 9 | 10 | `cd Python-3.6.3/` 11 | 12 | 稍微解释上面这句命令,这句话的大致目的就是把python的安装目录指定一下,这样的话,里面的一些bin目录、lib目录就都会存放在这个目录下面。 13 | 14 | `./configure --prefix=/usr/local/python3Dir` 15 | 16 | 如果报错就表示gcc组件没有安装 17 | 18 | `yum install -y gcc` 19 | 20 | 编译源码 21 | 22 | `make` 23 | 24 | 执行安装 25 | 26 | `make install` 27 | 28 | 出现错误 29 | `zipimport.ZipImportError: can't decompress data; zlib not available 30 | make: *** [install] 错误 1` 31 | 32 | 安装zlib相关的依赖包 33 | 34 | yum -y install zlib* 35 | -------------------------------------------------------------------------------- /doc/notes/tomcat/IO模型.md: -------------------------------------------------------------------------------- 1 | # 单线程阻塞模型 2 | 3 | ![1569671010390](../../images/1569671010390.png) 4 | 5 | 特点 6 | 7 | * 单线程:服务端只有一个线程处理客户端的所有请求 8 | * 阻塞I/O 在读写线程的时候是阻塞的,读取客户端数据要等待客户端发送数据并且把操作系统内核的数据复制到用户进程才能解决阻塞。 9 | 10 | 缺点 11 | 12 | * 性能很差,只有一个线程处理数据,当前线程正在处理请求的时候,无法处理其他请求。 13 | 14 | 15 | 16 | # 多线程阻塞模型 17 | 18 | ![1569671454613](../../images/1569671454613.png) 19 | 20 | 利用多线程机制多分配一个线程,当多个请求过来的时候,服务器端在接受客户端请求后,分别创建多个线程对他们进行处理。客户端与服务器线程的比例是1:1 21 | 22 | 特点 23 | 24 | * 能够提高服务器端的并发处理能力,但是每个线程需要分配一个线程池进行操作。 25 | * 多线程需要上下文切换。 26 | 27 | # 单线程非阻塞 I/O 模型 28 | 29 | 单线程非阻塞I/O模型的最大特点是,在调用读取和写入接口后立马返回,而不是阻塞。 30 | 31 | 探讨单线程非阻塞I/O 模型先了解一下非阻塞情况下的套字节检测机制。 32 | 33 | * 应用程序遍历套字节时间检测,尝试读写。使用一个线程负责遍历套字节列表,同时处理数据的拼凑。 34 | * 内核遍历套字节检测: -------------------------------------------------------------------------------- /doc/notes/algorithm(算法)/DP 区间问题.md: -------------------------------------------------------------------------------- 1 | 我们主要通过三道子序列问题来分析 2 | 首先DP区间问题可以通过大问题划分成最优的子结构来解决。 3 | 也就是说每个最终解都是从子问题开始的。 4 | 5 | * 516.longest-palindromic-subsequence 6 | Given a string s, find the longest palindromic subsequence's length in s. 7 | 我们采用一个二维的数组来记录历史,`dp[i][j]`表示的是索引`i`-`j`之间的最大字串。 8 | 我们可以发现下面三个情况: 9 | * len=1 的时候表示`dp[i][j]`就只有一个字符,`dp[i][j]=1` 10 | * `str[i]==str[j]`就表示是回文,`dp[i][j] = dp[i+1][j-1]+2` 11 | * 否则不是在前就是在后。 12 | 13 | 针对如何遍历所有序列我们采用这样的方式 14 | ```java 15 | for(int len=1;len<=s.length();len++){ 16 | // 起始位置 17 | for(int i=0;i<=s.length()-len;i++){ 18 | // j的位置 19 | int j = i+len-1; 20 | // do something 21 | } 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /doc/notes/java/面经/Kyligence实习.md: -------------------------------------------------------------------------------- 1 | 一面 2 | 3 | 问的十分基础 4 | 5 | java 的所有基本类型 6 | 7 | String 是可变类型吗 String的实现有什么不同 8 | 9 | volatile 的几个作用 10 | 11 | final 的作用 12 | 13 | 有什么问题? 14 | 15 | 作为程序员在Kyligence 的一天是怎么样的? 16 | 17 | 然后聊天 18 | 19 | 20 | 21 | 二面 22 | 23 | 讲一下你对泛型的理解 24 | 25 | 能不能声明一个 List a = new ArrayList 并且 B 继承 A 26 | 27 | 三次握手 为什么要有三次握手 28 | 29 | 基于 TCP 设计一个文件上传的协议(emmm 爱奇艺三面问到) 30 | 31 | 垃圾回收机制 讲一个你比较熟悉的垃圾回收器 32 | 33 | 手撕代码(纸上) 34 | 35 | 三个线程ABC 反复交替打印 A B C 撕了 36 | 37 | 实现一个计算器 没有括号 两个栈就完事了 撕了 38 | 39 | 有什么问题? 40 | 41 | 贵公司如何做code review的? 42 | 43 | 44 | 45 | 三面 46 | 47 | leader 好像不知道我来面的什么岗 48 | 49 | 我随口说了个实习生 50 | 51 | 我人都傻了 52 | 53 | 然后让我等offer邮件 54 | 55 | 56 | 57 | HR 58 | 59 | 主要问了一下意向 看到钱那么少我也没什么兴趣,直言钱太少,意向不大 60 | 61 | 估计不会发offer了 -------------------------------------------------------------------------------- /doc/notes/java/面经/支付宝风控部门一面.md: -------------------------------------------------------------------------------- 1 | * 遇到的反爬虫 2 | * robot.txt 3 | * user-agent 4 | * cookie加密 5 | * ip 封禁 6 | 7 | * 验证码怎么破解 8 | 9 | * 知道CNN技术吗 10 | * 答了 卷积神经网络 11 | 12 | * ~~布隆过滤器误判率~~ 在redis的书上有 13 | * 为什么会上布隆过滤器 14 | * mysql 查询优化是怎么优化的 15 | * 用between and 如果用 * 就可以走主键索引 16 | * 但是使用limit 去 * 不符合最左前缀 就会导致不走索引 全量查询 17 | * 用了ORM吗 用什么连接驱动 18 | * 用了mysqldb 没有pymysql 19 | * DB里面的事务 20 | 讲了事务隔离机制 21 | * 将一下未提交读 22 | * 讲一下串行读 面试官讲了秒杀场景 可以适用 23 | * 爬虫的DFS 有遇到循环的问题吗 24 | * 为什么没有用BFS 用的DFS 25 | * DFS 栈溢出 问题 26 | * 布隆过滤器bit数 hash数目是怎么选择的 27 | * bit 9000w 100M hash 数目 28 | * 1亿的请求的log 请求独立的ip数目 29 | * 聊一下java反射 30 | * 你直接的 server 打算支持 HTTPS 31 | * Django ORM 了解吗 讲一下ORM 32 | * ORM N+1 遇到过吗 33 | * elasticsearch 了解过吗 34 | * 爬虫有爬html吗 35 | * 怎么做增量 36 | * 增量怎么才能避免全量爬 37 | -------------------------------------------------------------------------------- /doc/notes/java/面经/头条二面.md: -------------------------------------------------------------------------------- 1 | 在爱奇艺做了什么? 排障 2 | 3 | 负载均衡算法 怎么 把流量打均匀 session(redis) 4 | 5 | 一个对象的生命周期 6 | 7 | JVM 是怎么创建一个线程的 8 | 9 | * 两台机子最多能建立多少个TCP链接 10 | 11 | 主机{ip,port} - 客户端{ip,port} 12 | 13 | ipv4的长度是32位,得2^32,端口16位,得2^16,共计**2^48。同时还要受限与最大文件描述符数目及内存限制** 14 | 15 | * 为什么要有三次握手和四次挥手 16 | 17 | * 三次握手怎么匹配 sq number 18 | 19 | 布隆过滤器怎么调参 20 | 21 | 布隆过滤器的哈希函数是自己实现的吗? 不是 22 | 23 | 为什么wait time 是2MSL 如果是10MSL 20MSL 会怎么样 24 | 25 | MSL 是怎么算出来的? 26 | 27 | NIO 的核心理念是什么?为什么叫NIO 28 | 29 | NIO 多路复用select() epoll() 演进流程 同步到异步 30 | 31 | 原子类线程调度的关系 32 | 33 | JVM 内存模型(你给我说清楚 是JVM 还是JMM) 34 | 35 | * 一定要有老年代和新生代吗 没有没关系吗? 36 | 37 | 这个主要看JVM 规范 38 | 39 | * JMM 工作内存 和 主内存主要是什么 40 | 41 | 栈数据区 操作数 42 | 43 | JMM 最重要的准则是什么 happens before ? 44 | 45 | JVM 运行时候数据模型是怎么样的? 46 | 47 | 老年代垃圾回收算法 48 | 49 | happens before 原则运用 50 | 51 | 实现热加载主要解决了什么问题 热加载 我说重新new 类加载器 他好像不满意?? 52 | 53 | 双亲委派怎么实现的 解决了什么问题 54 | 55 | 解决碎片 不怎么了解垃圾回收器? 解决碎片主要用什么收集器? 56 | 57 | 反转链表 -------------------------------------------------------------------------------- /doc/notes/linux/git.md: -------------------------------------------------------------------------------- 1 | ### 创建本地分支推到服务器 2 | 创建新的本地分支 3 | `git checkout -b dd ` 4 | 5 | 从远程拉取分支 6 | `git checkout -b dd remote/origin/dd` 7 | 8 | 创建远程分支 9 | `git push origin dd:dd` 10 | 11 | ### 切换远程服务地址 12 | 13 | 删除远程服务器地址 14 | `git remote rm origin` 15 | 16 | 添加新的 17 | `git remote add origin https://github.com/xiantang/jdcrawler` 18 | 19 | ### 添加多个远程源 20 | 21 | 查看远程源 `git remote -v` 22 | 23 | ``` 24 | origin ssh://a.git (fetch) 25 | origin ssh://a.git (push) 26 | ``` 27 | 28 | 添加一个名为 us 远程源 29 | 30 | `git remote add us ssh://c.git` 31 | 32 | 查看远程源 `git remote -v` 33 | 34 | ``` 35 | origin ssh://a.git (fetch) 36 | origin ssh://a.git (push) 37 | us ssh://b.git (fetch) 38 | us ssh://b.git (push) 39 | 40 | ``` 41 | 42 | 获取所有远程分支到本地 `git fetch --all` 43 | 44 | 45 | 46 | 复原submodule 47 | 48 | `git submodule foreach --recursive git reset --hard` 49 | `git submodule update --init --recursive` 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /doc/notes/algorithm(算法)/tree.md: -------------------------------------------------------------------------------- 1 | ## 霍夫曼树 2 | 霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。 3 | 4 | * 根据给定的n个权值(W1,W2...Wn),使对应节点构成n个二叉树的森林T=(T1,T2...Tn),其中每个二叉树Ti(1 <= i <= n)中都有一个带权值为Wi的根节点,其左、右子树均为空。 5 | * 在森林T中选取两个节点权值最小的子树,分别作为左、右子树构造一个新的二叉树,且置新的二叉树的根节点的权值为其左右子树上根节点权值之和。 6 | * 在森林T中,用新得到的二叉树替代选取的两个二叉树。 7 | 重复2和3,直到T只包含一个树为止。这个数就是霍夫曼树。 8 | 9 | ## 平衡二叉树 10 | 它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。 11 | 12 | ![â€œå¹³è¡¡äºŒå‰æ ‘â€çš„å›¾ç‰‡æœç´¢ç»“æžœ](../../images/Sun, 26 May 2019 235539.jpeg) 13 | 14 | ### AVL 15 | 16 | * 它的左子树和右子树都是平衡二叉树。 17 | 18 | * 左子树和右子树的深度之差的绝对值不超过1。 19 | 20 | ![img](../../images/avl_right_rotation.jpg) 21 | 22 | ### B-树 23 | * 所有叶子结点位于同一层,并且 不带信息。 24 | * 树中每个节点最多有m个子树(即至多含有m-1个关键字)。 25 | * 若根节点不是终端节点,则根节点子树[2,m]. 26 | * 除根节点外其他非叶子节点至少有[m/2]个子树(即至少含有[m/2]-1个关键字)。 27 | ![“b-æ ‘â€çš„å›¾ç‰‡æœç´¢ç»“æžœ](../../images/Sun, 26 May 2019 235747.jpeg) 28 | 29 | 30 | ### B树 和 B+树的区别 31 | * B+树种所有叶子节点包含了全部关键字,即其他非叶子节点中的关键字包含在叶子节点中,而在B-树中,关键字是不重复的。 32 | * B+树中所有非叶子节点仅起到索引的作用 -------------------------------------------------------------------------------- /doc/notes/scala/常用命令.md: -------------------------------------------------------------------------------- 1 | Sbt. 2 | 3 | ### 常用命令[ ](https://www.scala-sbt.org/1.x/docs/zh-cn/Running.html#常用命令) 4 | 5 | 下面是一些非常常用的的 sbt 命令。更加详细的列表请参见 [命令行参考](https://www.scala-sbt.org/1.x/docs/docs/Command-Line-Reference.html)。 6 | 7 | | `clean` | 删除所有生成的文件 (在 `target` 目录下)。 | 8 | | ------------- | ------------------------------------------------------------ | 9 | | `compile` | 编译源文件(在 `src/main/scala` 和 `src/main/java` 目录下)。 | 10 | | `test` | 编译和运行所有测试。 | 11 | | `console` | 进入到一个包含所有编译的文件和所有依赖的 classpath 的 Scala 解析器。输入 `:quit`, Ctrl+D (Unix),或者 Ctrl+Z (Windows) 返回到 sbt。 | 12 | | `run <参数>*` | 在和 sbt 所处的同一个虚拟机上执行项目的 main class。 | 13 | | `package` | 将 `src/main/resources` 下的文件和 `src/main/scala` 以及 `src/main/java` 中编译出来的 class 文件打包成一个 jar 文件。 | 14 | | `help <命令>` | 显示指定的命令的详细帮助信息。如果没有指定命令,会显示所有命令的简介。 | 15 | | `reload` | 重新加载构建定义(`build.sbt`, `project/*.scala`, `project/*.sbt` 这些文件中定义的内容)。在修改了构建定义文件之后需要重新加载。 | -------------------------------------------------------------------------------- /doc/notes/linux/命令.md: -------------------------------------------------------------------------------- 1 | ## ngrok 内网映射 2 | 3 | ./ngrok authtoken 5ioHp3Qr1ztsMz9adXTH7_5GF6YTpEnczVrjGvmyd6R 4 | 5 | 6 | 7 | ./ngrok http 80 8 | 9 | 10 | 11 | 12 | 13 | ## 重启nginx 14 | 15 | 16 | 17 | `ps -ef | grep nginx ` 18 | 19 | 从容停止 kill -QUIT 主进程号 20 | 快速停止 kill -TERM 主进程号 21 | 强制停止 kill -9 nginx 22 | 23 | 关闭nginx 开机自动启动 24 | `systemctl disable nginx.service` 25 | 26 | 重启`redis` 27 | 28 | `etc/init.d/redis-server restart` 29 | 验证密码 30 | 31 | `auth 123456zjd` 32 | >OK 33 | 34 | 远程连接 35 | 36 | `redis-cli -h 111.231.255.225 -p 6379` 37 | 38 | scrapy-redis 设置密码 39 | 40 | ```python3 41 | REDIS_URL = 'redis://:{psw}@{host}:{port}'.format( 42 | host='111.231.255.225', # your server ip 43 | port='6379', 44 | psw='123456zjd', 45 | ) 46 | ``` 47 | 48 | 49 | 查找指定进程 50 | ` ps -ef | grep mmp-front //mmp-front是进程关键字` 51 | 52 | 53 | 54 | ### VNC 55 | 56 | 关闭指定屏幕 57 | 58 | vncserver -kill :1 59 | 60 | 开启屏幕 61 | 62 | vncserver -geometry 1440x900 :1 63 | 64 | -------------------------------------------------------------------------------- /README.en-US.md: -------------------------------------------------------------------------------- 1 | |    Algorithm    | Operating System |    Network    | Object Oriented |   Database    |    Java    | System Design |    Tools    | Coding Practices |    framework    | 2 | | :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:| 3 | | [:pencil2:](#pencil2-Algorithm) | [:computer:](#computer-OperatingSystem)|[:cloud:](#cloud-Network) | [:art:](#art-ObjectOriented) |[:floppy_disk:](#floppy_disk-Database)| [:coffee:](#coffee-java)| [:bulb:](#bulb-SystemDesign)| [:wrench:](#wrench-Tools)| [:watermelon:](#watermelon-CodingPractices)| [:rocket:](#rocket-framework) | 4 | 5 | 6 | Other languages: 7 | 8 | - [English](README.en-US.md) 9 | - [简体中文](README.md) 10 | 11 | ## :pencil2: Algorithm 12 | 13 | - [《Grokking Algorithms》 notes](https://github.com/xiantang/grokking_algorithms) 14 | - [《Algorithms 4th》 notes](https://github.com/xiantang/algorithm) 15 | 16 | -------------------------------------------------------------------------------- /doc/notes/bigdata(大数据)/BloomFilter.md: -------------------------------------------------------------------------------- 1 | ## 算法描述 2 | 3 | 一个empty bloom filter是一个有m bits的bit array,每一个bit位都初始化为0。并且定义有k个不同的hash function,每个都以uniform random distribution将元素hash到m个不同位置中的一个。在下面的介绍中n为元素数,m为布隆过滤器或哈希表的slot数,k为布隆过滤器重hash function数。 4 | 5 | ## 添加一个元素 6 | 7 | 用k个hash function 将hash得到的bloom filter中的k个bit位 置为1。 8 | 9 | ## 查询元素是否存在 10 | 11 | 用k个hash function 将他的hash得到k个bit位,如果任意一位为0,则这个元素必不存在。 12 | 13 | ## 误判 14 | 15 | 当add 的元素过多,n/m(n元素数目 m 是bloom filter的bit数目) 过大,会导致false positive 此时就需要重新组建filter,但这种情况相对少见。 16 | 17 | ## 优势 18 | 19 | ### 时间 20 | add 和 query 时间复杂度只有 O(k) 21 | ### 空间 22 | 对于一个有1%误报率和一个最优k值的布隆过滤器来说,无论元素的类型及大小,每个元素只需要9.6 bits来存储。 23 | 24 | ![](http://ww1.sinaimg.cn/large/006d4JA0ly1g1pebftymgj30lh0lkjs6.jpg) 25 | 26 | 当 -1/m 很大 并且趋于0的时候误判率会降低,n降低也会使误判率降低。 27 | 28 | 29 | ![](http://ww1.sinaimg.cn/large/006d4JA0ly1g1pfb746nkj30lp0q5ab3.jpg) 30 | 31 | 输入 1000w 误判率1% 32 | 计算占用空间9000w bit 100M 这样 并且空间占用率50% 33 | m = 9000w 34 | n = 1000w 35 | 36 | hashfunction 0.7*9 = 7 37 | 38 | ### 空间占用估计 : 39 | 40 | k=0.7*(l/n) # 约等于 41 | f=0.6185^(l/n) # ^ 表示次方计算,也就是 math.pow 42 | 43 | 对于1亿个url 我们使误判率在0.1%的情况 下,可以计算出他所需要的哈希函数的个数为多少。然后得出所需要占用的空间为多少。 -------------------------------------------------------------------------------- /doc/notes/algorithm(算法)/剑值offer 刷题集合/回溯.md: -------------------------------------------------------------------------------- 1 | # 字符串的排列 2 | 3 | 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 4 | 5 | 可以画出一个递归树 6 | 7 | ![1569674676555](../doc/images/1569674676555.png) 8 | 9 | 每次递归都将当前的字母和之后的字母交换,然后不断深入。 10 | 11 | ```java 12 | import java.util.*; 13 | public class Solution { 14 | private ArrayList result; 15 | private TreeSet paths = new TreeSet<>(); 16 | public ArrayList Permutation(String str) { 17 | 18 | result = new ArrayList<>(); 19 | if(str .equals("") ){ 20 | return result; 21 | } 22 | find(str,0); 23 | result.addAll(paths); 24 | return result; 25 | } 26 | 27 | public void find(String str,int index){ 28 | if(index == str.length()){ 29 | paths.add(str); 30 | return; 31 | } 32 | for(int i = index;i width) { 45 | print(fileName+": "+line.trim) 46 | } 47 | } 48 | val source = Source.fromFile(fileName) 49 | for(line <- source.getLines()){ 50 | processLine(line) 51 | } 52 | } 53 | } 54 | ``` 55 | 56 | 57 | 58 | ## 一等函数 59 | 60 | 函数字面量: 存在于源码. 61 | 62 | 函数值:以对象的形式存在于运行时. 63 | 64 | ```scala 65 | var increase = (x :Int) => x+1 66 | ``` 67 | 68 | => 表示该函数将左侧的内容(任何整数X) 转换为右侧的内容(x +1)。 将任何整数x 映射成为x+1 的函数. 69 | 70 | 71 | -------------------------------------------------------------------------------- /doc/notes/work(工作)/AES 限制长度.md: -------------------------------------------------------------------------------- 1 | 写了一个工具类用来加密解密数据库的 app字段 2 | 3 | 本地环境运行单测什么都没有任何问题,但是一到生产环境就出现 BUG。 4 | 5 | ![image-20191109145633818](/Users/xiantang/Library/Application Support/typora-user-images/image-20191109145633818.png) 6 | 7 | 这个的原因是因为线上环境没有支持 AES 算法的 Provider 需要通过改 ext 包下添加支持的第三方包或者引入第三方库解决。 8 | 9 | 我这边采用的是引入第三方库: 10 | 11 | ```scala 12 | "org.bouncycastle" % "bcprov-jdk16" % "1.45" 13 | ``` 14 | 15 | ```scala 16 | private val localCipher: ThreadLocal[Cipher] = ThreadLocal.withInitial(() => Cipher.getInstance("AES/ECB/PKCS5Padding", new BouncyCastleProvider())) 17 | ``` 18 | 19 | 这样就解决了 No installed provider supports this key 的问题。 20 | 21 | 但是提到了测试环境,又出现了问题: 22 | 23 | ![image-20191109150457772](/Users/xiantang/Library/Application Support/typora-user-images/image-20191109150457772.png) 24 | 25 | 显示没有合法的AES key 26 | 27 | 首先我先将 SEED 的长度设置到16个字符,本地没有问题但是测试环境仍然报错,我突然发现我的 SEED 会进行一次 SHA-256 算法的散列,随后他的字符数目会增加到 32 个。 28 | 29 | 我们需要明确一下本地环境和线上环境的不同: 30 | 31 | * 本地: Jdk 安全目录 含有 unlimit 的jar包,也就是支持 16 24 32 位的key 32 | * 线上: Jdk 安全目录 只含有 limit 的jar包,只支持 16 位的key 33 | 34 | 有两种解决方式1.线上安装 unlimit 的jar包 2. 使用16位的key 35 | 36 | 因为线上是容器环境,比较难更改 jdk jar 包,所以采用第二种。 37 | 38 | 只需要将对 SEED 加密的散列算法改为 MD5 加密就行,因为MD5 会将SEED 转换为一个长度为 16 个字符的字符串。 39 | 40 | ```groovy 41 | import java.nio.charset.StandardCharsets 42 | import java.security.MessageDigest 43 | 44 | String a = "----------------" 45 | def instance = MessageDigest.getInstance("MD5") 46 | secret = instance.digest(a.getBytes()) 47 | new String(secret).length() 48 | ``` -------------------------------------------------------------------------------- /doc/notes/java/idea.md: -------------------------------------------------------------------------------- 1 | ## 在 Intelij IDEA 中修改 maven 为国内镜像 2 | 3 | 国内镜像:阿里 4 | 打开 IntelliJ IDEA->Settings ->Build, Execution, Deployment -> Build Tools > Maven 5 | 或者直接搜索 maven 6 | 具体如下图所示: 7 | 而一般情况下在 c:\Users\xx.m2 \ 这个目录下面没有 settings.xml 文件,我们可以新建一个,settings.xml 文件下的内容是:直接粘贴复制保存在上图所示的目录下面就可以了. 需要注意的是,需要点击上图所示右下角的 override。 8 | 9 | ```xml 10 | 14 | 15 | 16 | 17 | alimaven 18 | aliyun maven 19 | http://maven.aliyun.com/nexus/content/groups/public/ 20 | central 21 | 22 | 23 | 24 | ``` 25 | 26 | 27 | 如果是 linux 系统,操作过程基本相同,只是 settings.xml 文件的存放路径不一样,不过都可以通过上面截图所示的页面中查到。 28 | 29 | 30 | 31 | ## idea 常用快捷键 32 | 33 | ctrl+N 生成代码 34 | 35 | ctrl+shift+A 命令全搜索. 36 | This is almost always followed by Ctrl + Alt + Left to get back to where I was (Ctrl + Alt + Right works to “go forward” again). 37 | Ctrl+N 创建class 38 | 39 | Ctrl + J 查看方法JavaDoc 40 | 41 | 42 | 43 | 44 | 45 | ## 自动导入静态包 46 | 47 | `command+enter` 对于测试的很多静态方法无法方便的导入。 48 | 需要添加对模糊的包进行导入就可以完成 49 | 50 | ``` 51 | Perferences->Editor->General->Auto Import->java->add unambigous import on fly 52 | ``` 53 | 54 | -------------------------------------------------------------------------------- /doc/notes/middware(中间件)/kafka.md: -------------------------------------------------------------------------------- 1 | kafka 基础知识 2 | 3 | ![kafka](http://matt33.com/images/2015-11-14-kafka-introduce/kafka.png) 4 | 5 | - **Topic**:特指Kafka处理的消息源的不同分类,其实也可以理解为对不同消息源的区分的一个标识; 6 | - **Partition**:Topic物理上的分组,一个topic可以设置为多个partition,每个partition都是一个有序的队列,partition中的每条消息都会被分配一个有序的id(offset); 7 | - **Message**:消息,是通信的基本单位,每个producer可以向一个topic(主题)发送一些消息; 8 | - **Producers**:消息和数据生产者,向Kafka的一个topic发送消息的过程叫做producers(producer可以选择向topic哪一个partition发送数据)。 9 | - **Consumers**:消息和数据消费者,接收topics并处理其发布的消息的过程叫做consumer,同一个topic的数据可以被多个consumer接收; 10 | - **Broker**:缓存代理,Kafka集群中的一台或多台服务器统称为broker。 11 | 12 | ![log](http://matt33.com/images/2015-11-14-kafka-introduce/log.png) 13 | 14 | 在调用conusmer API时,一般都会指定一个consumer group,该group订阅的topic的每一条消息都发送到这个group的某一台机器上。借用官网一张图来详细介绍一下这种情况,假如kafka集群有两台broker,集群上有一个topic,它有4个partition,partition 0和1在broker1上,partition 2和3在broker2上,这时有两个consumer group同时订阅这个topic,其中一个group有2个consumer,另一个consumer有4个consumer,则它们的订阅消息情况如下图所示: 15 | 16 | [![consumerGroup](http://matt33.com/images/2015-11-14-kafka-introduce/consumerGroup.png)](http://matt33.com/images/2015-11-14-kafka-introduce/consumerGroup.png)consumerGroup 17 | 18 | 因为group A只有两个consumer,所以一个consumer会消费两个partition;而group B有4个consumer,一个consumer会去消费一个partition。这里要注意的是,kafka可以保证一个**partition内的数据是有序的**,所以group B中的consumer收到的数据是可以保证有序的,但是Group A中的consumer就无法保证了。 19 | 20 | group读取topic,**partition分配**机制是: 21 | 22 | - 如果group中的consumer数小于topic中的partition数,那么group中的consumer就会消费多个partition; 23 | - 如果group中的consumer数等于topic中的partition数,那么group中的一个consumer就会消费topic中的一个partition; 24 | - 如果group中的consumer数大于topic中的partition数,那么group中就会有一部分的consumer处于空闲状态。 -------------------------------------------------------------------------------- /doc/notes/java/面经/蚂蚁金服网商银行一面.md: -------------------------------------------------------------------------------- 1 | * ~~1500w数据怎么用redis去重 (答了布隆过滤器)~~ 2 | 3 | * ~~AB两个索引 是复合索引 where B="?" 会走复合索引吗?~~ 4 | * 利用索引中的附加列可以减少搜索的范围,但使用一个具有两列的索引 不同于使用两个单独的索引。如果您知道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处。 5 | * 在创建复合索引的时候,应该仔细考虑列的顺序。索引中的所有列执行搜索,或者针对前几条的搜索可以使用复合索引。 6 | * 最左前缀原则是最左优先,以最左边的为起点任何连续的索引都能匹配上 7 | 8 | 9 | * ~~1500w 怎么确定between and 范围~~ 10 | 11 | * ~~怎么优化1500w数据中一个区间的数据的查询(我答了limit 1)~~ 12 | 13 | * ~~有限状态机的概念~~ 14 | 15 | * ~~有限状态机在某个状态出现问题 怎么处理 怎么返回原来的状态~~ 16 | 17 | 18 | * ~~事务中出现了长时间操作该如何处理~~ 19 | 20 | 21 | * ~~事务的隔离级别(我答了事务传播。。。。。)~~ 22 | * READ UNCOMMITTED(未提交读) 23 | 事务的修改即使没有提交对其他事务都是可见的,事务可以读取未提交的数据也就被称为脏读(Dirty Read) 24 | 一般很少使用。 25 | * READ COMMITED(提交读) 26 | 一个事务开始的时候只能“看见”已经提交事务所做的修改,也就是说一个事务从开始到提交之前,所做的任何修改 27 | 都是对其他事务不可见的。 28 | * REPEATABLE READ(可重复读) 29 | MySQL 的默认事务隔离级别 30 | 无法解决环行(Phantom Row) 31 | * SERIALIZABLE(可串行化) 32 | 33 | * ~~开启事务的时候update一个数据 被另一个数据操作了怎么处理~~ 34 | 35 | * ~~mysql 的锁 了解过吗?~~ 36 | 37 | * ~~线程池了解吗~~ 38 | 39 | * ~~synchronized 和显式的Lock 锁有什么区别 答了字面意思~~ 40 | 41 | * ~~sysnchronized底层实现 在集群下的特性~~ 42 | 43 | * ~~两台机器分布式部署一个应用 sysnchronized 怎么锁~~ 44 | 45 | 多线程同时写一个商品的最低价格 并发一个写3快 一个写4块 怎么能保证写最低价格 46 | 47 | 48 | * ~~为什么在wait()外面要包while循环~~ 49 | 50 | 51 | rabbitMq 消费者无法接收 消费者重复接收 52 | 53 | 如果rabbitMq 在发送邮件的时候,邮件服务器挂了怎么办(面试官说太依赖redis了。。。) 54 | 55 | 数据库只是在用的层面(面试官评价) 56 | 57 | Java多线程在写吗? 58 | 59 | 线程池是如何工作的? 60 | 61 | Thread sleep()和join()的区别 62 | 63 | sleep()会释放锁吗? 64 | 65 | Thread run() 和 start()区别 66 | 67 | 双亲委派模型 68 | 69 | Java的内存回收机制 70 | -------------------------------------------------------------------------------- /doc/notes/network(计算机网络)/internet.md: -------------------------------------------------------------------------------- 1 | # 计算机网络 2 | 3 | ## 网络分层 4 | * 应用层:网络进程到应用程序。针对也定的应用规定各层协议。端系统用软件实现。 5 | * 表示层:负责数据的加密解密,把数据转换成独立于机器的数据。 6 | * 会话层:主机间通讯,管理应用程序之间的会话。 7 | * 传输层:在网络的各个节点之前可靠的分发数据包。 8 | * 网络层:进行地址分配和路由。 9 | * 数据链路层:可靠的点对点数据直链。 10 | * 物理层:不一定可靠的点对点数据直链。 11 | 12 | ## 底层网络协议 13 | 14 | ### ARP 15 | 基本功能为透过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。在每台安装有TCP/IP协议的电脑或路由器里都有一个ARP缓存表,表里的IP地址与MAC地址是一对应的。 16 | 17 | ### NAT 18 | 基本功能为透过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。在每台安装有TCP/IP协议的电脑或路由器里都有一个ARP缓存表,表里的IP地址与MAC地址是一对应的。 19 | 20 | 21 | # HTTP 协议 22 | * 构建在TCP/IP协议之上 默认端口号80 23 | * 无连接无状态 24 | 25 | ## 状态码含义 26 | * 1** 服务器收到请求,需要请求者继续执行操作。 27 | * 2** 成功,操作被成功接收并处理。 28 | * 3** 重定向,需要进一步的操作以完成请求。 29 | * 301 Moved Permanently。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 30 | * 302 Moved Temporarily。与301类似。但资源只是临时被移动。客户端应继续使用原有URI 31 | * 304 Not Modified。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源。 32 | * 4** 客户端错误,请求包含语法错误或无法完成请求 33 | * 400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。 34 | * 401 Unauthorized 请求未经授权。这个状态代码必须和WWW-Authenticate报头域一起使用 35 | * 403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因 36 | * 404 Not Found 请求的资源不存在,例如,输入了错误的UR 37 | * 5** 服务器错误,服务器在处理请求的过程中发生了错误 38 | * 500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。 39 | * 503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常。 40 | 41 | ## GET 和 POST 的区别 42 | 43 | GET可提交的数据量受到URL长度的限制,HTTP协议规范没有对URL长度进行限制。这个限制是特定的浏览器及服务器对它的限制。 44 | 理论上讲,POST是没有大小限制的,HTTP协议规范也没有进行大小限制,出于安全考虑,服务器软件在实现时会做一定限制。 45 | 46 | ## Http会话的过程 47 | * 建立tcp连接 48 | * 发出请求文档 49 | * 发出响应文档 50 | * 释放tcp连接 51 | 52 | 53 | 54 | ### IPV6 缩写 55 | 56 | 1. 连续段的0可以用::来省略(单个的也可以) 但是最多只能出现一次 57 | 2. 单个0000可以简化成0 例如: FE80:0000:0000:0000:AAAA:0000:00C2:0002 等价于 FE80:0:0:0:AAAA:0000:00C2:0002 58 | 3. 前导的0可以被省略 59 | 60 | -------------------------------------------------------------------------------- /doc/notes/fp(函数式编程)/如何学习函数式编程与Scala.md: -------------------------------------------------------------------------------- 1 | ## 背景: 2 | 3 | 刚来到以scala为技术栈的公司的时候,配置了半天环境,然后终于将项目起了起来,发现里面的代码很奇怪,没有任何循环,数据的操作是一个函数套着一个函数,十分令人疑惑,于是借着业务需求和这股好奇劲开始学习关于scala的内容。 4 | 5 | ## 目标: 6 | 7 | 1. 熟练运用项目中的异步操作 Future 变换 (同步思维转异步) 8 | 2. 熟悉 Play 框架能够熟练的翻文档解决问题 9 | 3. 熟练运用高阶函数 map flatMap 等操作 10 | 11 | ### 阶段 1:能写 Scala 12 | 13 | 这个阶段比较容易达到,就是首先需要阅读 《[Scala编程](https://www.douban.com/link2/?url=https%3A%2F%2Fbook.douban.com%2Fsubject%2F5377415%2F&query=scala+编程&cat_id=1001&type=search&pos=1)》前几章 或者 [推特scala课堂](https://twitter.github.io/scala_school/zh_cn/index.html) ,来了解scala的基本语法。但是在这个阶段仍然会有很多的坑,基本是在 IDEA 的提示 与 爆红下才能勉强的写代码。 14 | 15 | ### 阶段2: 知道函数式编程是什么东西 16 | 17 | 当你差不多写了半个月 Scala 之后,仍然好奇函数式编程是什么东西,这个时候你就可以去学习一些关于函数式编程的知识了,我的线路是先学习了 [programming-languages](https://www.coursera.org/learn/programming-languages/home/welcome) 这门入门课程,主要讲了一些关于函数式编程的基础知识,包括但不限于 闭包 高阶函数 尾递归 代数类型。 虽然语言不是Scala 但是这门课为我之后的函数式编程打下了一定的基础。 如果你在这门课上认真的完成了作业,后面的路会通畅很多。 18 | 19 | ### 阶段3:再深入的了解 20 | 21 | 到这个时候,你一定会听到一本十分有名的书《Scala 函数式编程》 这本书,很有可能在你没经历前几个阶段的时候,你就看了,但是发觉里面的内容十分抽象,便放弃了。现在你就可以大胆的去看它了,可以无痛的看到第六章。 22 | 23 | 再在下面,就会被更抽象的 Monad Factor 等概念所迷惑。 24 | 25 | ### 阶段4:持续学习基础 26 | 27 | 上面的阻塞其实还是因为对基础知识不够扎实,所以还是需要进一步的学习,这里推荐 Scala 语言作者的课程 [Functional Programming Principles in Scala](https://www.coursera.org/learn/progfun1/home/welcome) . 因为不是免费的,所以需要付费或者采用奖学金(咸鱼)来免费学习。这门课程虽然不及上面的 programming-languages 课程,但是比较困难的习题还是能提升FP的水平的。 28 | 29 | ### 阶段5:参与社区 30 | 31 | 这个时候你就可以继续去看 《Scala 函数式编程》 这本书了,因为你看完了上面的两门全英文课程所以英文也不会再惧怕就可以参与社区了,这里推荐几个比较好的社区,曾经给我过帮助的社区 https://gitter.im/scala/scala. https://gitter.im/akka/akka , 如果对开源有兴趣,就可以给 akka 或者 Play 修复BUG了。 32 | 33 | 最后推荐一些给我过帮助的网站 34 | 35 | [coursera.org](http://coursera.org/) 网课平台 36 | 37 | https://www.playframework.com/ play 官网 38 | 39 | https://stackoverflow.com/ scala 模块 基本99%的scala 问题都能在上面找到,前提是会搜索 40 | 41 | https://github.com/ 找轮子 -------------------------------------------------------------------------------- /doc/notes/work(工作)/sonar.md: -------------------------------------------------------------------------------- 1 | 安装 SonarScanner https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/ 2 | 3 | 下载[Mac OS X 64-bit](https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.2.0.1873-macosx.zip) 版本 4 | 5 | 6 | 7 | 配置环境变量 8 | 9 | ```shell 10 | vim ~/.bash_profile 11 | export SONAR_SCANNER_HOME=/yourpath/sonar-scanner-4.2.0.1873-macosx/ 12 | source ~/.bash_profile 13 | ``` 14 | 15 | 16 | 17 | Plugin.sbt 18 | 19 | ```scala 20 | addSbtPlugin("com.github.mwz" % "sbt-sonar" % "1.3.0") 21 | addSbtPlugin("com.github.sbt" % "sbt-jacoco" % "3.1.0") 22 | ``` 23 | 24 | sonar-project.properties 25 | 26 | ```properties 27 | # more parameters https://docs.sonarqube.org/display/SONAR/Analysis+Parameters 28 | # must be unique in a given SonarQube instance 29 | sonar.projectKey=com.growingio:growing-marketing 30 | # this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1. 31 | sonar.projectName=growing-marketing 32 | sonar.projectVersion=1.0 33 | sonar.host.url = http://sonarqube.growingio.com 34 | 35 | # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. 36 | # This property is optional if sonar.modules is set. 37 | sonar.sources=app 38 | sonar.tests=test 39 | 40 | # set the classes path for sonar findbugs plugin 41 | sonar.java.binaries=target/scala-2.12/classes 42 | 43 | # Encoding of the source code. Default is default system encoding 44 | sonar.sourceEncoding=UTF-8 45 | 46 | # run `sbt jacoco` to generate the report 47 | sonar.coverage.jacoco.xmlReportPaths=target/scala-2.12/jacoco/report/jacoco.xml 48 | ``` 49 | 50 | 51 | 52 | Build.sbt 53 | 54 | ```scala 55 | enablePlugins(JacocoPlugin) 56 | jacocoReportSettings := JacocoReportSettings ( 57 | "Jacoco Coverage Report", 58 | None, 59 | JacocoThresholds(), 60 | Seq(JacocoReportFormats.ScalaHTML, JacocoReportFormats.XML), 61 | "utf-8" 62 | ) 63 | ``` 64 | 65 | 66 | 67 | 扫描项目: 68 | 69 | sbt sonarScan -------------------------------------------------------------------------------- /doc/notes/java/面经/支付宝一面.md: -------------------------------------------------------------------------------- 1 | 对象存在的周期 2 | 3 | java的垃圾回收器 几个 4 | 5 | 爬虫项目怎么监控价格 6 | 7 | redis单点还是集群化 单点可靠性 8 | 9 | fork 是 new 一个子进程 10 | 11 | redis 在超出内存的情况下怎样进行IO操作 12 | 13 | 如何学习的 是学习java 还是python 14 | 15 | * Java 实现切面变成 和 依赖注入 为什么c/C++不能这样做(扯到了编程范式 java的包访问机制) 16 | 通过反射实例化对象,存入到Spring的bean容器中 17 | 18 | 19 | 实例方法和静态方法不一样(感觉打得不够深入) 20 | 21 | 静态方法怎么用(我把单例模式全答了voliate 饿汉懒汉 枚举) 22 | 23 | 常见的异常类 (runtimeEx null classnot 索引溢出) 24 | 25 | classnotfound 情况 哪几种 (类加载器,环境变量没配(扯淡呢 环境变量没配根本找不到java)) 26 | 27 | * spring 事物传播机制 (woc 这是什么) 28 | 外围方法未开启事务的情况下Propagation.REQUIRED修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。 29 | Propagation.REQUIRED修饰的内部方法会加入到外围方法的事务中,所有Propagation.REQUIRED修饰的内部方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚。 30 | Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。 31 | Propagation.REQUIRES_NEW修饰的内部方法依然会单独开启独立事务,且与外部方法事务也独立,内部方法之间、内部方法和外部方法事务均相互独立,互不干扰。 32 | 33 | ThreadLocal 有啥作用(感觉答得不够深) 34 | 35 | session和cookie区别 session 怎么多服务器统一(答了redis) 36 | 37 | * 前端安全 XSS?? 38 | * XSS 攻击 39 | 通过html 注入 插入恶意脚本,前端没有经过检验就操作 40 | 使用正则通过标签替换进行解码 41 | * CSRF 攻击 42 | 登录网站种下cookie 不小心访问了恶意网站, 你的cookie被恶意网站捕获 请求地址中添加token。 43 | 44 | 45 | etc/hosts 有啥用 46 | 47 | 怎么监控内存 (top 用python glances) 48 | 49 | * 网络凉了 浏览器302 运用情况(背后逻辑) 50 | 当浏览器访问前面一个地址的时候,这个时候服务器会告知浏览器,请到B路径下获取这个文件,随后浏览器重新发起网络请求,请求B路径下的页面,经过渲染 51 | * http 1.1 怎么支持长链接 52 | Connection:keep-alive 53 | 有什么问题 (问了做什么业务 开舔) 54 | 55 | 56 | 57 | 58 | 59 | redis 实现集群 怎么实现hash 均匀 60 | 一致性hash采用去mod方法 一致性hash是对2^32次取模 61 | 哈希值空间组织成一个虚拟的圆环 62 | ![](https://pic1.zhimg.com/80/v2-fd44ab71c834f3fe458a6f76f3997f98_hd.jpg) 63 | 64 | 将各个服务器的名字进行一个hash 65 | ![](https://pic1.zhimg.com/80/v2-509993a49d447b378273e455a095de3c_hd.jpg) 66 | 数据key使用相同的hash函数计算出hash 定位在环上 67 | ![](https://pic4.zhimg.com/80/v2-4fab60735dfae0bf511709e9d337789b_hd.jpg) 68 | 根据逆时针行走,每个数据都会被定位在指定服务器上 69 | 一致性Hash算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。 70 | 71 | 节点较少不均匀的情况下,怎么操作 72 | ![](https://pic3.zhimg.com/80/v2-d499324a9aa067915bbb3f5f3416b032_hd.jpg) 73 | 采用虚拟节点技术,每个节点计算多个hash 74 | ![](https://pic3.zhimg.com/80/v2-0368841e5020dd07f1e67f449b49a1ba_hd.jpg) -------------------------------------------------------------------------------- /doc/notes/algorithm(算法)/图.md: -------------------------------------------------------------------------------- 1 | ## 133.Clone Graph 2 | 3 | 4 | Given a reference of a node in a `connected` undirected graph, return a `deep copy `(clone) of the graph. Each node in the graph contains a val (int) and a list (List[Node]) of its neighbors. 5 | 6 | ![](https://assets.leetcode.com/uploads/2019/02/19/113_sample.png) 7 | 8 | 9 | ``` 10 | 11 | Input: 12 | {"$id":"1","neighbors":[{"$id":"2","neighbors":[{"$ref":"1"},{"$id":"3","neighbors":[{"$ref":"2"},{"$id":"4","neighbors":[{"$ref":"3"},{"$ref":"1"}],"val":4}],"val":3}],"val":2},{"$ref":"4"}],"val":1} 13 | 14 | Explanation: 15 | Node 1's value is 1, and it has two neighbors: Node 2 and 4. 16 | Node 2's value is 2, and it has two neighbors: Node 1 and 3. 17 | Node 3's value is 3, and it has two neighbors: Node 2 and 4. 18 | Node 4's value is 4, and it has two neighbors: Node 1 and 3. 19 | 20 | ``` 21 | 22 | 一看到这道题 我就想用dfs去做,传入一个引用给他进行实例化,实例化的成员变量在设置进去 23 | 24 | 但是出现了问题,会栈溢出,经过debug 突然发现这个是一个无向图,所以需要添加一个map进行去重 防止重复遍历,但是又存在一个问题,如果他是重复的但是也是一个neighbor应该如何拿到那个引用呢,这里我用一个hashMap 存入之前的引用,需要的时候获取就行了。 25 | 26 | 27 | ```java 28 | /* 29 | // Definition for a Node. 30 | class Node { 31 | public int val; 32 | public List neighbors; 33 | 34 | public Node() {} 35 | 36 | public Node(int _val,List _neighbors) { 37 | val = _val; 38 | neighbors = _neighbors; 39 | } 40 | }; 41 | */ 42 | class Solution { 43 | Map map = new HashMap<>(); 44 | public Node cloneGraph(Node node) { 45 | if(node == null){ 46 | return null; 47 | } 48 | 49 | return dfs(node); 50 | } 51 | 52 | public Node dfs(Node node){ 53 | if(node == null){ 54 | return null; 55 | } 56 | if (map.containsKey(node.val)){ 57 | return map.get(node.val); 58 | } 59 | 60 | Node res = new Node(node.val, new ArrayList()); 61 | 62 | map.put(res.val,res); 63 | for (Node neighbor : node.neighbors) 64 | res.neighbors.add(dfs(neighbor)); 65 | return res; 66 | 67 | 68 | } 69 | } 70 | ``` -------------------------------------------------------------------------------- /doc/notes/algorithm(算法)/位运算.md: -------------------------------------------------------------------------------- 1 | # 78. Subsets 2 | 3 | 4 | Given a set of distinct integers, nums, return all possible subsets (the power set).Note: The solution set must not contain duplicate subsets.Example: 5 | 6 | ``` 7 | 8 | Input: nums = [1,2,3] 9 | Output: 10 | [ 11 | [3], 12 | [1], 13 | [2], 14 | [1,2,3], 15 | [1,3], 16 | [2,3], 17 | [1,2], 18 | [] 19 | ] 20 | ``` 21 | 22 | ![](http://ww1.sinaimg.cn/large/006d4JA0ly1g3er0g86xdj306z0ag746.jpg) 23 | 24 | 这种解法是 CareerCup 书上给的一种解法,想法也比较巧妙,把数组中所有的数分配一个状态,true 表示这个数在子集中出现,false 表示在子集中不出现,那么对于一个长度为n的数组,每个数字都有出现与不出现两种情况,所以共有 2n 中情况,那么我们把每种情况都转换出来就是子集了,我们还是用题目中的例子, [1 2 3] 这个数组共有8个子集,每个子集的序号的二进制表示,把是1的位对应原数组中的数字取出来就是一个子集,八种情况都取出来就是所有的子集了,参见代码如下 25 | 26 | 27 | 28 | ```java 29 | class Solution { 30 | public List> subsets(int[] nums) { 31 | int n = nums.length; 32 | List> res = new ArrayList<>(); 33 | for(int s=0;s< 1< cur = new ArrayList<>(); 35 | for(int i=0;i0){ 37 | cur.add(nums[i]); 38 | } 39 | } 40 | res.add(cur); 41 | 42 | } 43 | 44 | return res; 45 | } 46 | } 47 | ``` 48 | 49 | # 136. Single Number 50 | 51 | 52 | Given a non-empty array of integers, every element appears twice except for one. Find that single one. 53 | 54 | Note: 55 | Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? 56 | 57 | ``` 58 | Example 1: 59 | Input: [2,2,1] 60 | Output: 1 61 | 62 | Example 2: 63 | Input: [4,1,2,1,2] 64 | Output: 4 65 | ``` 66 | 67 | 68 | 69 | * If we take XOR of zero and some bit, it will return that bit 70 | * a⊕0=a 71 | 72 | 73 | * If we take XOR of two same bits, it will return 0 74 | * a⊕a=0 75 | 76 | * a⊕b⊕a=(a⊕a)⊕b=0⊕b=b 77 | 78 | 79 | ```java 80 | class Solution { 81 | public int singleNumber(int[] nums) { 82 | int a = 0; 83 | for(int i = 0;i fn z=> z>=y andalso y>=3` 的函数 68 | 69 | 下面你也可以通过柯里化来实现 fold map filter 这些函数 70 | 71 | ![image-20191129195217784](/Users/xiantang/Library/Application Support/typora-user-images/image-20191129195217784.png) -------------------------------------------------------------------------------- /doc/notes/java/面经/头条一面.md: -------------------------------------------------------------------------------- 1 | * static 的sync 和 实例的sync 2 | * 垃圾回收器 内存碎片 3 | * 二叉树的转链表 4 | * JVM 排查命令 5 | * JVM OOM 有哪几种情况 6 | * juc 下面的栅栏 这些类有了解过吗? 7 | * Java 内存模型 8 | * 线程池参数 主要作用 我爱小a 9 | * redis 数据结构 10 | * 有限状态机 11 | * CAS 是什么 ABA 问题 12 | * 分布式锁的实现 13 | * JVM 内存模型 14 | * 数据库索引的实现 叶子节点内部节点的区别 15 | * rabbitMQ 怎么用吗 16 | * java 的垃圾回收机制 17 | * HashMap 为什么线程不安全 场景 hashcode 怎么用 equal重写 18 | 19 | 对于一个指定位置的水坑,他所能承载的水的垂直数目取决于左右两边最高中的较小的那一块,所以通过遍历,就可以得出。 20 | 21 | ``` 22 | class Solution { 23 | public int trap(int[] height) { 24 | int sum = 0; 25 | int left = 0; 26 | int right = height.length-1; 27 | int left_max =0; 28 | int right_max = 0; 29 | while(leftleft_max){ 32 | left_max = height[left]; 33 | } 34 | else{ 35 | sum += left_max-height[left]; 36 | } 37 | left++; 38 | } 39 | else{ 40 | if(height[right]>right_max){ 41 | right_max = height[right]; 42 | } 43 | else{ 44 | sum += right_max-height[right]; 45 | } 46 | 47 | right--; 48 | } 49 | } 50 | return sum; 51 | } 52 | } 53 | ``` 54 | 55 | 用双指针来做,对于一个数组,我们分别定义left,right 如果height[left]>height[right] 说明right决定了这个位置水的容量 如果大于最大的就跟新小于就sum++ 56 | 57 | 58 | 59 | ### 内核态 和 用户态的区别 60 | 61 | [![img](https://github.com/xiantang/Java-BackEnd-Notes/raw/master/doc/images/431521-20160523163606881-813374140.png)](https://github.com/xiantang/Java-BackEnd-Notes/blob/master/doc/images/431521-20160523163606881-813374140.png) 62 | 63 | 内核本质是一种软件-控制操作系统的硬件资源,并提供上层应用程序运行的环境。 64 | 65 | 用户态:上层应用程序的活动空间,应用程序的执行必须依托于内核提供的资源,包括CPU资源、存储资源、I/O资源等。 66 | 67 | 为了让上层使用访问这些资源,内核必须为上层提供访问接口:系统调用 68 | 69 | 用户态可以使用三种方式访问内核态的资源: 70 | 71 | - 系统调用 72 | - 库函数 73 | - Shell 脚本 74 | 75 | Linux操作系统中主要采用了0和3两个特权级,分别对应的就是内核态和用户态。 76 | 77 | 运行于用户态的进程可以执行的操作和访问的资源都会受到极大的限制,而运行在内核态的进程则可以执行任何操作并且在资源的使用上没有限制。 78 | 79 | 很多程序开始运行于用户态,但是执行的过程中,一些操作需要在内核限权中执行,就涉及到一个**用户态切换到内核态的过程** -------------------------------------------------------------------------------- /doc/notes/java/JavaIO.md: -------------------------------------------------------------------------------- 1 | # Java IO 2 | ## StringBulider 和StringBuffer区别 3 | 4 | * String :字符串常量 5 | * StringBuffer 字符串变量(线程安全) 6 | * StringBuilder 字符串变量(非线程安全) 7 | 8 | **StringBuilder 和 StringBuffer 还有 String 的区别** 9 | * String是不可变对象 `public final class String`,每次改变等于生成了一个新的String对象。 10 | * StringBuffer是可变对象,每次改动都会对StringBuffer 对象本身进行改动。在某些情况下String 的改动被JVM解释称StringBuffer的拼接。 11 | * StringBuffer是线程安全的,一个类似String的字符串缓存区,不能修改。 12 | 因为可以安全的用于多个线程,所以在实例上的操作就想是串行的。 13 | * append():加入到字符缓冲区的末尾。 14 | * insert():替换指定位置 15 | * StringBuilder是StringBuffer的替换,在字符串缓冲区被单个线程使用的时候,优先使用该类。 16 | 17 | 18 | # NIO 19 | 20 | ## 多路复用模型 21 | 22 | 一个线程去轮询多个socket的状态,只有当socket真正有读写事件的时候,才会真正调用实际的IO操作。 23 | 另外多路复用 IO 为何比非阻塞 IO 模型的效率高是因为在非阻塞 IO 中,不断地询问 socket 状态 24 | 时通过用户线程去进行的,而在多路复用 IO 中,轮询每个 socket 状态是内核在进行的,这个效 25 | 率要比用户线程要高的多。 26 | 27 | ## Selector 28 | Selector 类是 NIO 的核心类,Selector 能够检测多个注册的通道上是否有事件发生,如果有事 29 | 件发生,便获取事件然后针对每个事件进行相应的响应处理。 30 | 31 | ## 流与块的比较 32 | 面向块的IO系统以块的形式处理数据。每一个操作都在一步中产生或消费一个数据块。按块要比按流快的多,但面向块的IO缺少了面向流IO所具有的有雅兴和简单性。 33 | 34 | 35 | 36 | Channel 是对于原IO流的模拟,来源和目的对象都必须通过Channel。Buffer实质是一个容器对象,发送给Channel 的所有对象都必须放到Buffer中。 37 | 38 | 39 | ## 同步、异步、阻塞与非阻塞 40 | 41 | 42 | * 同步:就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。 43 | * 异步:是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。 44 | 45 | ## Linux IO 模型 46 | 47 | ![](https://static.oschina.net/uploads/img/201604/20144245_Wtld.png) 48 | 49 | ## 同步阻塞 IO(blocking IO) 50 | 用户空间的应用程序执行一个系统调用,会导致程序阻塞,什么都不干,直到数据准备好。 51 | ![](https://static.oschina.net/uploads/img/201604/20150405_VKYH.png) 52 | 53 | ## 同步非阻塞 IO(nonblocking IO) 54 | 55 | 同步非阻塞就是 “每隔一会儿瞄一眼进度条” 的轮询(polling)方式。 56 | ![](https://static.oschina.net/uploads/img/201604/20152818_DXcj.png) 57 | 58 | 缺点:任务完成的响应延迟增大了,每隔一段时间才会轮询义词 read 操作,可能任务在两次轮询之间的任意时间完成。 59 | 60 | ## IO 多路复用( IO multiplexing) 61 | 62 | 由于同步非阻塞方式需要不断主动轮询,轮询占据了很大一部分过程,轮询会消耗大量的CPU时间,而 “后台” 可能有多个任务在同时进行,人们就想到了循环查询多个任务的完成状态,只要有任何一个任务完成,就去处理它。如果轮询不是进程的用户态,而是有人帮忙就好了,就是所谓的 “IO 多路复用” 63 | 64 | select 调用是内核级别的,select 轮询相对于非阻塞轮询的区别在于前者可以等待多个socket,能够实现对于过个IO端口的监控。 65 | 并且和阻塞IO的区别在于,select不是等到socket数据全部到达了再处理,而是有一部分数据就会调用用户线程处理。 66 | 67 | 当用户线程调用select,那么整个进程都会被block,内核会监控所有select负责的socket,如果任何一个socket准备好了,select返回,用户线程再调用read操作将数据从内核拷贝到用户线程。 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | |    算法    | 操作系统 |    网络    | 面向对象 |   数据库   |    Java    | 系统设计 |    工具    | 编码实践 |    框架    | 2 | | :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:| 3 | | [:pencil2:](#pencil2-算法) | [:computer:](#computer-操作系统)|[:cloud:](#cloud-网络) | [:art:](#art-面向对象) |[:floppy_disk:](#floppy_disk-数据库)| [:coffee:](#coffee-java)| [:bulb:](#bulb-系统设计)| [:wrench:](#wrench-工具)| [:watermelon:](#watermelon-编码实践)| [:rocket:](#rocket-框架) | 4 | 5 | 6 | Other languages: 7 | 8 | - [English](README.en-US.md) 9 | 10 | - [简体中文](README.md) 11 | 12 | 13 | 14 | ## :pencil2: 算法 15 | 16 | - [《算法图解》笔记](https://github.com/xiantang/grokking_algorithms) 17 | 18 | - [《算法4th》笔记](https://github.com/xiantang/algorithm) 19 | 20 | - [ Leetcode300](https://github.com/xiantang/leetcode) 21 | 22 | 23 | 24 | ## :cloud: 网络 25 | 26 | - [计算机网络总结](https://github.com/xiantang/Java-BackEnd-Notes/blob/master/doc/notes/network/internet.md) 27 | 28 | - [计算机网络概论笔记](https://github.com/xiantang/Java-BackEnd-Notes/blob/master/doc/notes/network/%E7%BD%91%E7%BB%9C%E6%A6%82%E8%AE%BA%E7%AC%94%E8%AE%B0.md) 29 | 30 | 31 | 32 | ## :coffee: Java 33 | 34 | - [《Java编程思想》笔记](https://github.com/xiantang/Java-BackEnd-Notes/blob/master/doc/notes/java/think%20in%20java.md) 35 | 36 | - Java面经(含有解答) 37 | * [JVM面试题](https://github.com/xiantang/Java-BackEnd-Notes/blob/master/doc/notes/java/JVM.md) 38 | 39 | * [Java集合类面试题](https://github.com/xiantang/Java-BackEnd-Notes/blob/master/doc/notes/java/JavaCollection.md) 40 | 41 | * [Java并发面试题](https://github.com/xiantang/Java-BackEnd-Notes/blob/master/doc/notes/java/JavaConcurrent.md) 42 | 43 | * [JavaIO面试题](https://github.com/xiantang/Java-BackEnd-Notes/blob/master/doc/notes/java/JavaIO.md) 44 | 45 | 46 | 47 | ## :computer: 操作系统 48 | 49 | * [docker 笔记]() 50 | 51 | 52 | 53 | ## :floppy_disk:数据库 54 | 55 | * [mysql笔记](https://github.com/xiantang/Java-BackEnd-Notes/tree/master/doc/notes/database/mysql) 56 | * [redis笔记](https://github.com/xiantang/Java-BackEnd-Notes/tree/master/doc/notes/database/redis) 57 | 58 | 59 | 60 | [我的博客](http://xiantang.info/) 61 | 62 | ​ -------------------------------------------------------------------------------- /doc/notes/java/面经/腾讯二面.md: -------------------------------------------------------------------------------- 1 | ~~JVM 排查命令~~ 2 | 3 | ~~JVM OOM 有哪几种情况~~ 4 | 5 | ~~juc 下面的栅栏 这些类有了解过吗?~~ 6 | 7 | ~~Java 内存模型~~ 8 | 9 | ~~线程池参数 主要作用 我爱小a~~ 10 | 11 | ~~redis 数据结构~~ 12 | 13 | ~~有限状态机~~ 14 | 15 | ~~CAS 是什么 ABA 问题~~ 16 | 17 | ~~分布式锁的实现~~ 18 | 19 | ~~数据库索引的实现 叶子节点内部节点的区别~~ 20 | 21 | 最左匹配对于ABC 如果A 相同 比较B 如果B相同比较C 22 | 23 | rabbitMQ 怎么用吗 24 | 25 | ~~java 的垃圾回收机制~~ 26 | 27 | ~~HashMap 为什么线程不安全 场景~~ 28 | 29 | ~~hashcode 怎么用 equal重写~~ 30 | 31 | 1. 自反性:对于任意的引用值x,x.equals(x)一定为true。  32 | 2. 对称性:对于任意的引用值x 和 y,当x.equals(y)返回true时,   y.equals(x)也一定返回true。  33 | 3. 传递性:对于任意的引用值x、y和z,如果x.equals(y)返回true,   并且y.equals(z)也返回true,那么x.equals(z)也一定返回true。  34 | 4. 一致性:对于任意的引用值x 和 y,如果用于equals比较的对象信息没有被修   改,多次调用x.equals(y)要么一致地返回true,要么一致地返回false。  35 | 5. 非空性:对于任意的非空引用值x,x.equals(null)一定返回false。  36 | 37 | ~~OOM 怎么排查~~ 38 | 39 | - 看堆栈 40 | 41 | 方法区 运行时常量池溢出 42 | 43 | 如果是 PermGen space 就代表属于方法区 44 | 45 | - 直接内存溢出 46 | 47 | Jmap 没有明确的信息 48 | 49 | 50 | 51 | 零拷贝:零拷贝描述的是CPU不执行拷贝数据从一个存储区域到另一个存储区域的任务,这通常用于通过网络传输一个文件时以减少CPU周期和内存带宽。 52 | 53 | ~~NIO bytebuffer~~ 54 | 55 | ~~类加载器 例子~~ 56 | 57 | # 堆外内存 之 DirectByteBuffer 详解 58 | 59 | https://www.jianshu.com/p/007052ee3773 60 | 61 | 哲学家问题: 62 | 63 | 为了不失一般性,我们假设有n个哲学家,围着餐桌思考宇宙、人生问题,每个哲学家面前有一个叉子与之对应,即:共有n个叉子;当哲学家思考一段时间后,他会拿起身边的2个叉子才能进食。进食完毕后,该哲学家放下叉子,继续思考人生、宇宙,如此往复,周而复始。 64 | 65 | 在解决该类问题时,属于竞争资源情形,假设所有哲学家均同时取得其同一方向(如左手边)的叉子时,可能出现了死锁问题。 66 | 67 | 二叉查找树 转排序的双向链表? 68 | 69 | ![](1562554585495](../../images/111938_nBce_222173.png) 70 | 71 | 给100w考生的成绩排序 基数排序 72 | 73 | 74 | 75 | 10w数找前100大的数 快排 76 | 77 | 二叉树的最小祖先 78 | 79 | ```java 80 | /** 81 | * Definition for a binary tree node. 82 | * public class TreeNode { 83 | * int val; 84 | * TreeNode left; 85 | * TreeNode right; 86 | * TreeNode(int x) { val = x; } 87 | * } 88 | */ 89 | class Solution { 90 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 91 | if(root == null || p == root || q == root ){ 92 | return root; 93 | } 94 | TreeNode left = lowestCommonAncestor(root.left,p,q); 95 | TreeNode right = lowestCommonAncestor(root.right,p,q); 96 | if(left!= null && right !=null){ 97 | return root; 98 | } 99 | if(left == null){ 100 | return right; 101 | }else{ 102 | return left; 103 | } 104 | } 105 | } 106 | ``` 107 | 108 | 先查看root是不是null 109 | 110 | 如果root 是 pq中的其中一个节点 立马返回 111 | 112 | 否则遍历左子树 找到左边是否有 p 或者q 113 | 114 | 再遍历右子树 115 | 116 | 查看root 是不是符合条件 117 | 118 | 如果left 不存在 就返回right 让上部接住 119 | 120 | right 同理 -------------------------------------------------------------------------------- /doc/notes/java/JavaCollection.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | * 集合类的各个使用环境 3 | 4 | # Java容器 5 | ## 集合体系结构 6 | 7 | 集合作为一个容器,可以存储多个元素,java提供了多种集合类。将集合类中共性的内容,不断向上抽取,最终形成了集合的体系结构。 8 | ![](https://img-blog.csdn.net/20150501232236784) 9 | 10 | Map和Set接口继承Collection 11 | List继承ListIterator和Collection 12 | Collection和ListIterator继承Iterator 13 | 14 | ## List和队列的区别 15 | 16 | Queue接口与List、Set同一级别,都是继承了Collection接口。 17 | LinkedList实现了Queue接口,Queue接口窄化了LinkedList其他方法的访问,就是如果接口参数是Queue的话,只能访问Queue定义的方法。 18 | 19 | ### 阻塞队列 20 | 试图向一个满的队列或者一个空的阻塞队列存入一个值的时候会阻塞线程。在多线程合作的时候阻塞线程是一个很好的工具。 21 | 22 | ### HashMap 和 HashTable 还有ConcurrentHashMap的区别 以及扩容机制 23 | HashTable 是传统的集合类 已经过时了,在Java4时候被重写了实现了Map接口。 24 | 25 | * 相同: 26 | * 都实现了Map接口 27 | * 不同: 28 | * 线程的安全性:HashMap不是synchronized的,HashTable是线程安全的。 29 | 多个线程可以共享HashTable,没有正确同步的话,多个线程是无法贡献HashMap的。Java5 提出的`ConcurrentHashMap`是`HashTable`的替代,共享性更好。 30 | * HashMap可以接受`null`的key和value,HashTable不行。 31 | * HashMap的迭代器是fail-fast的迭代器,但是Hashtable的enumerator迭代器不是fail-fast的。当有其他线程更改了HashMap的结构,就会抛出`ConcurrentModificationException`。由于在同一时刻只有一个线程修改`ConcurrentHashMap`所以不需要抛出这个异常。 32 | * Hashtable 线程安全使用的是synchronized,因为这个是JVM关键字,是重型操作,所以在单线程下还是HashMap效率高。`ConcurrentHashMap`使用的是CAS技术,也就是乐观锁。当多个线程需要修改同一个变量时候只有其中一个线程能更新,其他线程都失败,失败的线程不会挂起,而是告知这次竞赛失败。先获取key的hashCode,如果是空的就初始化,初始化的时候如果`sizeCtl`被修改就直接yield当前线程。![](https://img-blog.csdn.net/20160318105849333) 如果CAS竞赛成功就创建新的table。 33 | 34 | ### 重写equals() 传什么参 35 | 36 | 37 | 1. 自反性:对于任意的引用值x,x.equals(x)一定为true。  38 | 2. 对称性:对于任意的引用值x 和 y,当x.equals(y)返回true时,   y.equals(x)也一定返回true。  39 | 3. 传递性:对于任意的引用值x、y和z,如果x.equals(y)返回true,   并且y.equals(z)也返回true,那么x.equals(z)也一定返回true。  40 | 4. 一致性:对于任意的引用值x 和 y,如果用于equals比较的对象信息没有被修   改,多次调用x.equals(y)要么一致地返回true,要么一致地返回false。  41 | 5. 非空性:对于任意的非空引用值x,x.equals(null)一定返回false。  42 | 43 | 44 | ### HashMap源码解析 45 | HashMap 主要用来存放键值对,它基于哈希表的Map接口实现,是常用的Java集合之一。 46 | * JDK1.8 之前由数组和链表组成,链表主要为了解决冲突 47 | * JDK1.8 之后在解决hash冲突的时候采取了较大变化,链表长度大于8链表转换为红黑树(log n)。 48 | * 初始容量16,尽量先预估自己的数据量来设置初始值。 49 | 50 | JDK1.8转换红黑树 51 | ![](https://camo.githubusercontent.com/20de7e465cac279842851258ec4d1ec1c4d3d7d1/687474703a2f2f6d792d626c6f672d746f2d7573652e6f73732d636e2d6265696a696e672e616c6979756e63732e636f6d2f31382d382d32322f36373233333736342e6a7067) 52 | 53 | 当链表数组的容量大于初始容量的0.75的时候,散列将链表扩大为2倍,把原来的数组搬移到新的数组中。 54 | 55 | 为什么0.75 56 | 57 | * node 在 bin 中 遵循泊松分布 58 | * 用0.75 作为加载因子的时候 59 | * 0: 0.60653066 60 | * 1: 0.30326533 61 | * 2: 0.07581633 62 | * 3: 0.01263606 63 | * 4: 0.00157952 64 | * 5: 0.00015795 65 | * 6: 0.00001316 66 | * 7: 0.00000094 67 | * 8: 0.00000006 68 | 69 | 树化主要是为了避免hash攻击 并且hashmap 在扩容因子为0.75的情况下 70 | 他的转换为树的概率是0.000006% 所以基本是不会转换为树的 71 | 除非是刻意的将不同的对象设置为相同hashcode 的 hash碰撞攻击 72 | -------------------------------------------------------------------------------- /doc/notes/algorithm(算法)/剑值offer 刷题集合/二叉树.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 二叉树中和为某一值的路径 4 | 5 | ## 题目描述 6 | 7 | 输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前) 8 | 9 | ```java 10 | import java.util.*; 11 | /** 12 | public class TreeNode { 13 | int val = 0; 14 | TreeNode left = null; 15 | TreeNode right = null; 16 | 17 | public TreeNode(int val) { 18 | this.val = val; 19 | 20 | } 21 | 22 | } 23 | */ 24 | public class Solution { 25 | public ArrayList> result; 26 | public ArrayList> FindPath(TreeNode root,int target) { 27 | result = new ArrayList<>(); 28 | find(root,target,new ArrayList()); 29 | return result; 30 | } 31 | public void find(TreeNode root,int target,ArrayList current) { 32 | if(root == null){ 33 | return; 34 | } 35 | if(root.val == target && root.left ==null &&root.right == null){ 36 | current.add(root.val); 37 | result.add(new ArrayList<>(current)); 38 | current.remove(current.size()-1); 39 | }else if(root.val < target){ 40 | current.add(root.val); 41 | find(root.left,target-root.val,current); 42 | find(root.right,target-root.val,current); 43 | current.remove(current.size()-1); 44 | } 45 | 46 | } 47 | } 48 | ``` 49 | 50 | 从根节点开始先序遍历,并且只用一个current 的list集合,遇到一个节点判断是否比target 小 如果比target 小就继续减去当前的值,继续遍历左子树和右子树,如果值相同,就看看是不是叶子节点如果是叶子节点就深拷贝一个list result 以为arrayList 是引用类型,记得每次添加元素都需要对应删除元素,以为引用类型会在上个方法返回之后继续生效。 51 | 52 | 53 | 54 | # 复杂链表的复制 55 | 56 | ## 题目描述 57 | 58 | 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空) 59 | 60 | ```java 61 | import java.util.*; 62 | /* 63 | public class RandomListNode { 64 | int label; 65 | RandomListNode next = null; 66 | RandomListNode random = null; 67 | 68 | RandomListNode(int label) { 69 | this.label = label; 70 | } 71 | } 72 | */ 73 | public class Solution { 74 | Map map = new HashMap<>(); 75 | public RandomListNode Clone(RandomListNode pHead){ 76 | if(pHead == null){ 77 | return null; 78 | } 79 | if(map.get(pHead) == null){ 80 | RandomListNode node = new RandomListNode(pHead.label); 81 | map.put(pHead,node); 82 | node.next = Clone(pHead.next); 83 | node.random = Clone(pHead.random); 84 | 85 | return node; 86 | }else{ 87 | return map.get(pHead); 88 | } 89 | 90 | } 91 | } 92 | ``` 93 | 94 | 这道题使用的是hashMap 存储的对应引用和新创建的对象,在dfs的时候先将当前对象给创建出来放置到Map 中这样遍历到的对象需要设置指向这个节点的指针的时候只需要从map 中取出对应的对象就行了。 -------------------------------------------------------------------------------- /doc/notes/database(数据库)/mysql/mysqlLock.md: -------------------------------------------------------------------------------- 1 | # 并发控制 2 | ## 读写锁 3 | 一个用户在阅读邮箱的时候,另一个用户试图删除这个邮件,就会产生不确定的后果。 4 | 并发控制:在处理并发读或者写的时候,通过实现一个由两种类型的锁组成的锁系统来解决问题 5 | 通常被称为共享锁和排他锁也叫`读锁`和`写锁`。 6 | 7 | 概念如下: 8 | * 读锁是共享的,或者说是互相不阻塞的,多个客户在同一时刻可以读取同一个资源,互相不干扰 9 | 。 10 | * 写锁是排他的,就是一个写锁会阻塞其他写锁和读锁。只有这样才能确保在给定时间里,只有一个用户执行写入 11 | 并防止其他用户读取正在写入的同一资源。 12 | 13 | ## 锁粒度 14 | 15 | ### 表锁 16 | 17 | 最基本的锁策略,并且是开销最小的策略,会首先锁定整张表,一个用户在对表进行 18 | 写操作(插入,删除,更新)需要先获得写锁,这会阻塞其他用户的所有读写操作。 19 | 只有没有写锁的情况下,其他读取用户才能获得读锁,读锁之间是不相互阻塞的。 20 | 锁的粒度较大,锁机制的开销小,并发能力较低。 21 | 在每个表结构加入一个互斥变量记录锁状态: 22 | ```C 23 | struct Table { 24 | Row rows[MAXROWS]; 25 | pthread_mutex_t lock;//表锁 26 | }; 27 | ``` 28 | 并发量上不去,因为无论多小的操作,都必须锁整个表,这可能带来其他操作的阻塞。 29 | 30 | ### 行级锁 31 | 32 | 行级锁只在存储引擎实现,服务层完全不了解存储引擎的锁实现。 33 | 行锁是如何实现的呢? Innodb 34 | # 事务 35 | 36 | ## ACID 37 | 事务就是一组原子性的sql查询,事务中的语句要么全部执行成功,要么全部执行失败。 38 | 系统必须通过严格的ACID测试,否则空谈事务的概念是不够的。 39 | ACID表示原子性,一致性,隔离性,持久性。 40 | 41 | * 原子性(atomicity) 42 | 事物必须视为一个不可分割的最小工作单元,整个事务中所有操作要么全部提交成功要么全部失败回滚 43 | * 一致性(consistency) 44 | 数据库总是从一个一致性的状态转换到另一个一致性的状态。 45 | * 隔离性(isolation) 46 | 一个事务所做的修改在最终提交以前,对其他事务是不可见的。 47 | * 持久性(duarbility) 48 | 一旦事务提交,则其所做的修改都会永久保存到数据库中。 49 | 50 | ## 隔离级别 51 | 52 | SQL标准定义了四种隔离级别,每一种级别都规定了一个事务所做的修改 53 | 54 | * READ UNCOMMITTED(未提交读) 55 | 事务的修改即使没有提交对其他事务都是可见的,事务可以读取未提交的数据也就被称为`脏读(Dirty Read)` 56 | 一般很少使用。 57 | * READ COMMITED(提交读) 58 | 一个事务开始的时候只能“看见”已经提交事务所做的修改,也就是说一个事务从开始到提交之前,所做的任何修改 59 | 都是对其他事务不可见的。 60 | 也叫不可重复读,因为一个事务中同样的两次操作会查出不同的结果。 61 | * REPEATABLE READ(可重复读) 62 | MySQL 的默认事务隔离级别 63 | 无法解决幻行(Phantom Row) 64 | 虽说解决了不可重复读(修改和删除)但是对于别的提交的事务插入的数据进行二次查询会发生幻行。 65 | * SERIALIZABLE(可串行化) 66 | ![](lock.png) 67 | 68 | 69 | | 隔离级别 | 特性 | 事务冲突情况 | 70 | |---| ----- | -------- | 71 | |未提交读| 事务的修改即使没有提交的事务是可见的 | 脏读(Dirty Read) | 72 | |提交读| 也较做不可重复读,一个事务只能看到已经提交事务所做的修改(修改删除) | 不可重复读 | 73 | |可重复读| MySQL默认的事务隔离级别,对于别的提交的事务插入数据进行二次查询会发生幻行(插入) |幻像读 | 74 | |可串行化|并发支持太差,最高级别的隔离| | 75 | 76 | ## 死锁 77 | 78 | 死锁指的是两个或者多个事务在同一资源上相互占用,并请求锁定对方占用资源,导致恶性循环的行为 79 | ![](dead.png) 80 | InnoDB 目前处理死锁的方法是,将持有最少行的排他锁事务进行回滚。 81 | 82 | 83 | ## 事务冲突情况 84 | 85 | 86 | 87 | * 脏读 88 | 当一个事务读取了另一个事务未提交的修改,产生脏读。 89 | ![](https://img-blog.csdn.net/20150928100835228?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 90 | * 不可重复读 91 | 统一查询在同一事务多次进行,但是由于其他事务所做的**修改**或者**删除**,每次返回回不同的结果集,此时发生幻像读。 92 | 93 | * 幻像读 94 | 同一查询在同一事务中多次进行,由于其他提交事务所做的**插入**操作,每次返回不同的结果集,此时发生幻像读。 95 | 96 | * 更新丢失 97 | 1. 第一类更新丢失,回滚覆盖。撤消一个事务时,在该事务内的写操作要回滚,把其它已提交的事务写入的数据覆盖了。 98 | 2. 第二类更新丢失,提交覆盖:提交一个事务时,写操作依赖于事务内读到的数据,读发生在其他事务提交前,写发生在其他事务提交后,把其他已提交的事务写入的数据覆盖了。这是不可重复读的特例。就是一个事务先读,然后中间发生了提交了的修改事务,但是当前事务没有察觉,就拿之前的数据去修改了。就覆盖了中间的更新。 99 | 100 | -------------------------------------------------------------------------------- /doc/notes/java/Quartz重复调度(任务重复执行)的问题排查.md: -------------------------------------------------------------------------------- 1 | * 序列化问题 2 | * 行锁保证线程安全 3 | * 类加载 4 | * 为什么事务就能保证安全了? 5 | 6 | 7 | 8 | 9 | 10 | 触发JOB fire 11 | 12 | **TRIGGER_STATE** 是当前trigger 的状态 **PREV_FIRE_TIME** 是上次触发的时间 13 | 14 | ![1565882162407](../../images/1565882162407.png) 15 | 16 | locks表 Quart 支持分布式,也就是会存在多个线程同时抢占资源的情况处理这种状况。 17 | 18 | ![图片描述](../../images/1910205370-5b441c7329be1_articlex.png) 19 | 20 | ```java 21 | protected T executeInNonManagedTXLock( 22 | String lockName, 23 | TransactionCallback txCallback, final TransactionValidator txValidator) throws JobPersistenceException { 24 | boolean transOwner = false; 25 | Connection conn = null; 26 | try { 27 | if (lockName != null) { 28 | // If we aren't using db locks, then delay getting DB connection 29 | // until after acquiring the lock since it isn't needed. 30 | if (getLockHandler().requiresConnection()) { 31 | conn = getNonManagedTXConnection(); 32 | } 33 | 34 | transOwner = getLockHandler().obtainLock(conn, lockName); 35 | } 36 | 37 | if (conn == null) { 38 | conn = getNonManagedTXConnection(); 39 | } 40 | 41 | final T result = txCallback.execute(conn); 42 | try { 43 | commitConnection(conn); 44 | } catch (JobPersistenceException e) { 45 | rollbackConnection(conn); 46 | if (txValidator == null || !retryExecuteInNonManagedTXLock(lockName, new TransactionCallback() { 47 | @Override 48 | public Boolean execute(Connection conn) throws JobPersistenceException { 49 | return txValidator.validate(conn, result); 50 | } 51 | })) { 52 | throw e; 53 | } 54 | } 55 | 56 | Long sigTime = clearAndGetSignalSchedulingChangeOnTxCompletion(); 57 | if(sigTime != null && sigTime >= 0) { 58 | signalSchedulingChangeImmediately(sigTime); 59 | } 60 | 61 | return result; 62 | } catch (JobPersistenceException e) { 63 | rollbackConnection(conn); 64 | throw e; 65 | } catch (RuntimeException e) { 66 | rollbackConnection(conn); 67 | throw new JobPersistenceException("Unexpected runtime exception: " 68 | + e.getMessage(), e); 69 | } finally { 70 | try { 71 | releaseLock(lockName, transOwner); 72 | } finally { 73 | cleanupConnection(conn); 74 | } 75 | } 76 | } 77 | ``` 78 | 79 | -------------------------------------------------------------------------------- /doc/notes/tomcat/折腾不止 手写Java Http server.md: -------------------------------------------------------------------------------- 1 | 这坑开了有三个多月了,是今年春招的时候开始写的方轮子。感觉很多基本的功能都已经完成了,下面分享上来给大家讲下写这个方轮子的心路历程。 2 | 3 | ## 起因 4 | 5 | 起初在牛客上看到一篇帖子 [《震惊!文科生如何三个月转行成为Java工程师? 》](https://www.nowcoder.com/discuss/156087) 这个作者自己写了一个HTTP server ,我突然想到为什么我不去实现一个呢? 6 | 7 | 因为其实在转到 Java(为了就业) 之前我是学习Python的,曾经用Python 实现过一个类似于 Scrapy 的爬虫框架,但是因为转到Java之后迫于繁杂的 Java 知识体系,也就没有想到写轮子这件事。但是这篇博客真的激起了我写轮子的欲望。 8 | 9 | 10 | 11 | ## 如何做?怎么做? 12 | 13 | 但是如何从头写一个服务器呢?就是模仿! 14 | 15 | 我看到那篇帖子的作者曾经提到他是看了一个Java SE的学习视频跟着慢慢写了一个1000多行的服务器,再自己慢慢迭代代码。 16 | 17 | 行!就这样,去找这个视频!但是发现 作者留下了一个失效百度云地址。不过这怎么能阻挡我写轮子的欲望,经过一下午的谷歌,终于找到了这个视频 [2018百战程序员JAVA全系列终结版第11阶:手写服务器httpserver项目](https://www.bilibili.com/video/av31470470/?p=3)。 18 | 19 | 是一个培训班的视频,起初我有些抵触,因为我觉得对我来说看培训班的视频的学习效率会不怎么高,没想到这个作者讲的十分的好,带我重新理解了一遍,web.xml 解析,反射解耦这些操作。花了两天的时间跟着视频做了一个十分简易的 BIO HTTP server。 20 | 21 | ## 看作者源码 22 | 23 | 一个简易的BIO server 并不使我满足,于是我开始去 Github 上学习作者的源码 [WebServer](https://github.com/songxinjianqwe/WebServer) 。当时还对 NIO 没有一个明确的概念,对于 reactor 模型没有一个深刻的概念,不过没有什么能阻挡我的,查阅了资料并且了解了 unix IO 模型之后的我就开始继续看着作者的源码写轮子。 24 | 25 | 期间主要实现了: 26 | 27 | ### NIO Reactor 28 | 29 | 我的实现是用一个 Acceptor 阻塞的获取Socket 连接,然后使用多个Poller 非阻塞轮询 socket 读事件,然后交给线程池处理。 30 | 31 | 其实对于线程池数目与Poller 的调参也有需要注意的点,我这边因为Poller的操作是计算密集型的操作所以选择了 CPU 核心数目+1 的方案,而后面的线程池我则使用的是200个线程(IO 密集型),而且需要注意的一点是对于溢出调度队列的线程,系统默认是采用抛出异常的方式,我这边采用的是 调用者执行的方式 使用主线程去串行的执行溢出的任务。这样的好处是会慢,但是也不会出现抛出异常的情况。 32 | 33 | ## 协同开发 34 | 35 | 这段时间,因为最最基础的功能已经开发完毕,所以我把我的轮子分享给牛客上认识的春招战友们一起开发。 36 | 37 | 我最要感谢的是和我一起开发的时候,一直交流的伙伴鸡哥,那段时间我们两个人满脑子都是轮子,考虑 NIO 考虑session的实现,聊到深夜,也与我反复重构了这个项目。 38 | 39 | 还有就是 offer 收割机表哥,他帮我指出了一个问题,就是 NIO selector 的注册不是并发的,当时我看 WebServer 的作者的时候也没有仔细思考。 40 | 41 | ```java 42 | private boolean events() { 43 | log.info("Queue大小为{},清空Queue,将连接到的Socket注册到selector中", events.size()); 44 | boolean result = false; 45 | PollerEvent pollerEvent; 46 | for (int i = 0, size = events.size(); i < size && (pollerEvent = events.poll()) != null; i++) { 47 | result = true; 48 | pollerEvent.run(); 49 | } 50 | return result; 51 | } 52 | ``` 53 | 54 | 后来修改为并发注册之后并发量提升了 10%。 55 | 56 | ## 继续迭代:Servlet 容器 57 | 58 | 于是我还是不满足,因为我的轮子这样的话就和 牛客的 NIO server 没有区别了,于是我查阅资料,其实我发现作者的 server 并没有引入servlet 容器这个概念。 59 | 60 | 于是我给自己定了三个小目标: 61 | 62 | * 引入 servlet 容器 63 | * 支持静态资源 64 | * 热加载实现 65 | 66 | 为了实现这个三个任务,我阅读了《深入刨析Tomcat》,也慢慢锻炼了自己的实现能力,因为这本书是BIO的实现并且代码贴的较少,所以跟着实现也是比较麻烦的,不过这能阻止的了我吗?冲就完事了。 67 | 68 | ### 支持静态资源 69 | 70 | 于是我先实现了静态资源的支持,看到图片和 jq 能够直接通过 `href`直接嵌入页面是一件多开心的事情啊! 71 | 72 | ![1561882183969](doc/images/1561882183969-1561883475753.png) 73 | 74 | ### 引入servlet容器 75 | 76 | 这个实现还是比较麻烦的,因为 Tomcat 的概念比较繁杂,需要先理解 Tomcat 的架构才行,我这边只是实现了 Context 和 Wrapper 两个容器,可以基本完成单应用程序。 77 | 78 | ![](https://segmentfault.com/img/remote/1460000009156128?w=550&h=358) 79 | 80 | ### 热加载实现 81 | 82 | 热加载这个是我这两天实现的,我这边独立出一个线程递归的扫描所有的 class 文件,然后重新创建一个自定义的类加载器,重新加载一遍指定的 servlet 再将指定的 servlet 实例重新放入 Wrapper 就能实现热加载。 83 | 84 | 这边的实现还是很简陋,需要进一步改进。 85 | 86 | 87 | 88 | ## 总结 89 | 90 | 希望能继续迭代下去吧,真的从这个轮子中学习到很多光看书和写CURD项目学不到的东西,不过代码写的不够优雅,需要再次重构这个项目,而且对于造轮子这件事情也不再惧怕了。如果有人想知道我具体实现的细节的话,我可以写一个这个轮子的实现细节。 91 | 92 | 项目链接:[ttps://github.com/xiantang/JerryMouse](https://github.com/xiantang/JerryMouse) 93 | 94 | 如果这个项目对你有帮助,或者我的学习经历使你对产生了兴趣请Star 或者参与进来。 95 | 96 | -------------------------------------------------------------------------------- /doc/notes/java/classLoader.md: -------------------------------------------------------------------------------- 1 | ### 实现容器热加载机制 2 | 3 | #### 什么是双亲委任模型? 4 | 双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派父类加载器去完成。每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个请求(他的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。 5 | 6 | 从Java 开发人员的角度来看,类加载还可以再细致一些,绝大部分Java 程序员都会使用以下 3 种系统提供的类加载器: 7 | 8 | * 启动类加载器(Bootstrap ClassLoader):这个类加载器复杂将存放在 JAVA_HOME/lib 目录中的,或者被-Xbootclasspath 参数所指定的路径种的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录下也不会重载)。 9 | * 扩展类加载器(Extension ClassLoader):这个类加载器由sun.misc.Launcher$ExtClassLoader实现,它负责夹杂JAVA_HOME/lib/ext 目录下的,或者被java.ext.dirs 系统变量所指定的路径种的所有类库。开发者可以直接使用扩展类加载器。 10 | * 应用程序类加载器(Application ClassLoader):这个类加载器由sun.misc.Launcher$AppClassLoader 实现。由于这个类加载器是ClassLoader 种的getSystemClassLoader方法的返回值,所以也成为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库。开发者可以直接使用这个类加载器,如果应用中没有定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。 11 | 12 | 13 | 14 | #### 双亲委派模型的好处 15 | 16 | ![](https://img-blog.csdn.net/20180508201301409?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Rhbmd3YW5tYTY0ODk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 17 | 18 | 双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派父类加载器去完成。每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个请求(他的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。 19 | 20 | 21 | 22 | #### 双亲委派是如何实现的呢? 23 | 24 | ```java 25 | 26 | protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException{ 27 | // First, check if the class has already been loaded 28 | Class c = findLoadedClass(name); 29 | if (c == null) { 30 | try { 31 | if (parent != null) { 32 | c = parent.loadClass(name, false); 33 | } else { 34 | c = findBootstrapClassOrNull(name); 35 | } 36 | } catch (ClassNotFoundException e) { 37 | // ClassNotFoundException thrown if class not found 38 | // from the non-null parent class loader 39 | } 40 | if (c == null) { 41 | // If still not found, then invoke findClass in order 42 | // to find the class. 43 | c = findClass(name); 44 | } 45 | } 46 | if (resolve) { 47 | resolveClass(c); 48 | } 49 | return c; 50 | } 51 | ``` 52 | 先检查是否被加载过,如果没有加载就调用父加载器的 loadClass 方法,如果父加载为空就默认使用启动类加载器作为父加载器。如果父类加载器加载失败,就抛出ClassNotFoundException 异常,再调用自己的findClass方法进行加载。 53 | 54 | 55 | #### 为什么要破坏双亲委派模型? 56 | 57 | 58 | 59 | 60 | 61 | ### ClassLoader.loadClass()与Class.forName()的区别 62 | 63 | ```java 64 | // 如果单纯使用new和用forName 其实没有特别大的区别 65 | // 都会去调用静态代码块,不过用forName 可以对代码进行解耦 66 | // jdk 现在主要实现了一个 driver接口 但是由于数据库的差异 67 | // jdk 会将这个driver的接口的子类交给厂商去实现 68 | // 实际上new Driver new出来的是com.mysql.什么什么的Driver 69 | // 数据库的信息你写在配置文件里面 70 | // 运行时的实例就是数据库产商实现的东西 71 | new com.mysql.jdbc.Driver(); 72 | String url = "jdbc:mysql://111.231.255.225:3306/db_example"; 73 | Connection connection = DriverManager.getConnection(url, "root", "123456zjd"); 74 | 75 | java.util.Enumeration driverEnumeration = DriverManager.getDrivers(); 76 | java.sql.Driver driver1 = driverEnumeration.nextElement(); 77 | 78 | System.out.println(driver1.getMajorVersion()); 79 | ``` 80 | 81 | -------------------------------------------------------------------------------- /doc/notes/work(工作)/docker skywalking.md: -------------------------------------------------------------------------------- 1 | # **Docker 部署 SkyWalking OAP & UI** 2 | 3 | ### ▶ 获取镜像 4 | 5 | > 当前版本:6.1.0 6 | > 自制镜像:[Docker 镜像 - 构建 SkyWalking OAP & UI](https://www.jianshu.com/p/a3a8d54b7da9) 7 | 8 | ``` 9 | # oap 10 | docker pull registry.cn-hangzhou.aliyuncs.com/anoy/skywalking-oap 11 | 12 | # ui 13 | docker pull registry.cn-hangzhou.aliyuncs.com/anoy/skywalking-ui 14 | ``` 15 | 16 | ### ▶ 部署 SkyWalking OAP 17 | 18 | **简易部署(仅供体验)** 19 | 20 | ``` 21 | docker run -d \ 22 | --name skywalking-oap \ 23 | -p 11800:11800 \ 24 | -e TZ=Asia/Shanghai \ 25 | registry.cn-hangzhou.aliyuncs.com/anoy/skywalking-oap 26 | ``` 27 | 28 | **端口说明** 29 | 30 | - `0.0.0.0/11800`:gRPC APIs,用于 Java、.NetCore、Node.js、Istio 探针 31 | - `0.0.0.0/12800`:http rest APIs,用于 SkyWalking UI 请求,做 GraphQL 查询 32 | 33 | **自定义配置** 34 | 35 | 配置挂载路径 `/skywalking/config`,配置文件说明: 36 | 37 | - `application.yml`:基本配置,参考 [application.yml](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fskywalking%2Fblob%2Fmaster%2Fdocker%2Fconfig%2Fapplication.yml) 38 | - `component-libraries.yml`:组件库配置,参考 [component-libraries.yml](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fskywalking%2Fblob%2Fmaster%2Fdocker%2Fconfig%2Fcomponent-libraries.yml) 39 | - `alarm-settings.yml`:报警配置,参考 [alarm-settings.yml](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fskywalking%2Fblob%2Fmaster%2Fdocker%2Fconfig%2Falarm-settings.yml) 40 | - `datasource-settings.properties`:数据库配置,参考 [datasource-settings.properties](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fskywalking%2Fblob%2Fmaster%2Fdocker%2Fconfig%2Fdatasource-settings.properties) 41 | - `log4j2.xml`:日志配置, 参考 [log4j2.xml](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fskywalking%2Fblob%2Fmaster%2Fdocker%2Fconfig%2Flog4j2.xml) 42 | 43 | ### ▶ 部署 SkyWalking UI 44 | 45 | ``` 46 | docker run -d \ 47 | --name skywalking-ui \ 48 | --link skywalking-oap:skywalking-oap \ 49 | -p 8088:8080 \ 50 | -e TZ=Asia/Shanghai \ 51 | registry.cn-hangzhou.aliyuncs.com/anoy/skywalking-ui \ 52 | --collector.ribbon.listOfServers=skywalking-oap:12800 \ 53 | --security.user.admin.password=admin 54 | ``` 55 | 56 | 参数说明: 57 | 58 | - `collector.ribbon.listOfServers`:SkyWalking OAP 地址,多个地址用 "," 分隔 59 | - `security.user..password`:指定登录的账号密码 60 | 61 | 更多配置参考:[https://github.com/apache/skywalking/blob/master/apm-webapp/src/main/resources/application.yml](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fskywalking%2Fblob%2Fmaster%2Fapm-webapp%2Fsrc%2Fmain%2Fresources%2Fapplication.yml) 62 | 63 | ### ▶ 访问 SkyWalking 64 | 65 | - 地址:[http://127.0.0.1:8088/](https://links.jianshu.com/go?to=http%3A%2F%2F127.0.0.1%3A8088%2F) 66 | - 账号:admin 67 | - 密码:admin 68 | 69 | 70 | 71 | play 集成scala 72 | 73 | 自定义一个task 74 | 75 | build.sbt 76 | 77 | ```scala 78 | import scala.sys.process._ 79 | lazy val agent = taskKey[Unit]("Execute clone skywalking-agent scripts") 80 | agent := { 81 | "git clone ssh://vcs-user@codes.growingio.com/source/skywalking-agent.git ./agent" ! 82 | } 83 | ``` 84 | 85 | 86 | 87 | 在 ./docker/build.sh 中添加执行task 的命令 88 | 89 | ```shell 90 | git submodule init 91 | git submodule update 92 | cd $home/growing-micros/ 93 | git checkout submodule 94 | cd ../ 95 | 96 | 97 | sbt agent <- here!!!! 98 | sbt dist 99 | cp target/universal/$archive_name $home/$base/ 100 | 101 | cd $home/$base/ 102 | ``` 103 | 104 | 105 | 106 | 107 | 108 | skywalking 有两个端,一个是服务端一个是客户端端,客户端是以javaagent 的方式嵌入到play 项目中 109 | 110 | -------------------------------------------------------------------------------- /doc/notes/linux/docker.md: -------------------------------------------------------------------------------- 1 | # 1、编写Scrapy的配置文件 2 | 3 | 4 | ```conf 5 | [scrapyd] 6 | eggs_dir = eggs 7 | logs_dir = logs 8 | items_dir = 9 | jobs_to_keep = 5 10 | dbs_dir = dbs 11 | max_proc = 0 12 | max_proc_per_cpu = 10 13 | finished_to_keep = 100 14 | poll_interval = 5.0 15 | bind_address = 0.0.0.0 16 | http_port = 6800 17 | debug = off 18 | runner = scrapyd.runner 19 | application = scrapyd.app.application 20 | launcher = scrapyd.launcher.Launcher 21 | webroot = scrapyd.website.Root 22 | 23 | [services] 24 | schedule.json = scrapyd.webservice.Schedule 25 | cancel.json = scrapyd.webservice.Cancel 26 | addversion.json = scrapyd.webservice.AddVersion 27 | listprojects.json = scrapyd.webservice.ListProjects 28 | listversions.json = scrapyd.webservice.ListVersions 29 | listspiders.json = scrapyd.webservice.ListSpiders 30 | delproject.json = scrapyd.webservice.DeleteProject 31 | delversion.json = scrapyd.webservice.DeleteVersion 32 | listjobs.json = scrapyd.webservice.ListJobs 33 | daemonstatus.json = scrapyd.webservice.DaemonStatus 34 | 35 | ``` 36 | 37 | ### 新建requirements 38 | 39 | `vim requirements.txt` 40 | 41 | ### Dockerfile 42 | 43 | `vi Dockerfile` 44 | 45 | ```dockerfile 46 | FROM python:3.5 47 | ADD . /code 48 | WORKDIR /code 49 | RUN pip install -r ./requirements.txt 50 | EXPOSE 6800 51 | COPY ./scrapyd.conf /etc/scrapyd/ 52 | CMD ["scrapyd"] 53 | ``` 54 | ### 建立镜像 55 | `docker build -t scrapyd:test .` 56 | 57 | ### 启动 58 | `docker run -d -p 6800:6800 scrapyd` 59 | 60 | ### 部署 61 | `scrapyd-deploy 0` 62 | 63 | ### 调度爬虫项目 64 | 65 | `curl http://111.231.255.225:6800/schedule.json -d project=jdcrawler -d spider=DetailSpider` 66 | 67 | ### 查看正在运行的容器 68 | 69 | `docker ps` 70 | 71 | ### 进入容器 72 | `sudo docker exec -it 0bf7d9d4aa4f bash` 73 | 74 | ### 部署爬虫项目 75 | `curl http://111.231.255.225:6800/schedule.json -d project=jdcrawler -d spider=DetailSpider` 76 | 77 | ### 取消某个爬虫 78 | `curl http://xiantang.info:6800/cancel.json -d project=jdcrawler -d job=65edbff03cd911e9ae0f0242ac110002` 79 | 80 | * 登录阿里云Docker Registry 81 | `$ sudo docker login --username=战神皮皮迪 registry.cn-hangzhou.aliyuncs.com` 82 | 用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。您可以在产品控制台首页修改登录密码。 83 | * 从Registry中拉取镜像 84 | `$ sudo docker pull registry.cn-hangzhou.aliyuncs.com/xiantang/xiantang:[镜像版本号]` 85 | * 将镜像推送到Registry 86 | ```shell 87 | $ sudo docker login --username=战神皮皮迪 registry.cn-hangzhou.aliyuncs.com 88 | $ sudo docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/xiantang/xiantang:[镜像版本号] 89 | $ sudo docker push registry.cn-hangzhou.aliyuncs.com/xiantang/xiantan:[镜像版本号] 90 | ``` 91 | 请根据实际镜像信息替换示例中的[ImageId]和[镜像版本号]参数。 92 | 93 | 94 | # docker 常用命令 95 | 96 | 查看所有正在运行容器 97 | `docker ps ` 98 | 99 | 查看所有容器 100 | `docker ps -a` 101 | 102 | 关闭指定容器 103 | `docker stop [containerId]` 104 | 105 | 删除已经退出的镜像 106 | 107 | ` 108 | docker rm -v $(docker ps -a -q -f status=exited)` 109 | 110 | ## 删除所有的镜像 111 | 112 | ```shell 113 | docker rmi $(docker images -q) 114 | ``` 115 | 116 | # Ubuntu 16.04 安装 Docker 117 | 118 | 1.选择国内的云服务商,这里选择阿里云为例 119 | `curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -` 120 | 121 | 2.安装所需要的包 122 | `sudo apt-get install linux-image-extra-$(uname -r) linux-image-extra-virtual` 123 | 124 | 125 | 3.添加使用 HTTPS 传输的软件包以及 CA 证书 126 | 127 | ```shell 128 | sudo apt-get update 129 | sudo apt-get install apt-transport-https ca-certificates 130 | ``` 131 | 132 | 4.添加GPG密钥 133 | ` 134 | sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D 135 | ` 136 | 137 | 5.添加软件源`echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list` 138 | 6.添加成功后更新软件包缓存`sudo apt-get update` 139 | 7.安装docker 140 | `sudo apt-get install docker-engine` 141 | 8.启动 docker 142 | ` sudo systemctl enable docker` 143 | `sudo systemctl start docker` -------------------------------------------------------------------------------- /doc/notes/algorithm(算法)/貪心.md: -------------------------------------------------------------------------------- 1 | ## 455. Assign Cookies 2 | 3 | Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at most one cookie. Each child i has a greed factor gi, which is the minimum size of a cookie that the child will be content with; and each cookie j has a size sj. If sj >= gi, we can assign the cookie j to the child i, and the child i will be content. Your goal is to maximize the number of your content children and output the maximum number. 4 | 5 | 6 | 7 | Example 1: 8 | ``` 9 | Input: [1,2,3], [1,1] 10 | 11 | Output: 1 12 | 13 | Explanation: You have 3 children and 2 cookies. The greed factors of 3 children are 1, 2, 3. 14 | And even though you have 2 cookies, since their size is both 1, you could only make the child whose greed factor is 1 content. 15 | You need to output 1 16 | ``` 17 | 18 | 19 | Example 2: 20 | 21 | ``` 22 | 23 | Input: [1,2], [1,2,3] 24 | 25 | Output: 2 26 | 27 | Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2. 28 | You have 3 cookies and their sizes are big enough to gratify all of the children, 29 | You need to output 2. 30 | ``` 31 | 一眼就是貪心算法,首先我們可以這樣想,我們需要返回的是滿足的數目。由於list1 是升序的所以我們只要滿足前面的孩子就行了,後面的需要付出更高的代價 32 | 33 | ``` 34 | class Solution { 35 | public int findContentChildren(int[] g, int[] s) { 36 | Arrays.sort(g); 37 | Arrays.sort(s); 38 | int i = 0, j = 0; 39 | while(i < g.length && j < s.length) { 40 | if(s[j]>=g[i]){ 41 | i++; 42 | j++; 43 | } 44 | else j++; 45 | } 46 | return i; 47 | } 48 | } 49 | 50 | ``` 51 | 52 | 53 | ## 134. Gas Station 54 | 55 | 56 | 57 | There are N gas stations along a circular route, where the amount of gas at station i is gas[i].You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.Return the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return -1. 58 | 59 | 60 | 61 | **Note:** 62 | * If there exists a solution, it is guaranteed to be unique. 63 | * Both input arrays are non-empty and have the same length. 64 | * Each element in the input arrays is a non-negative integer. 65 | 66 | 67 | 68 | **Example 1:** 69 | 70 | ``` 71 | Input: 72 | 73 | gas = [1,2,3,4,5] 74 | cost = [3,4,5,1,2] 75 | 76 | Output: 3 77 | 78 | Explanation: 79 | Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4 80 | Travel to station 4. Your tank = 4 - 1 + 5 = 8 81 | Travel to station 0. Your tank = 8 - 2 + 1 = 7 82 | Travel to station 1. Your tank = 7 - 3 + 2 = 6 83 | Travel to station 2. Your tank = 6 - 4 + 3 = 5 84 | Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3. 85 | Therefore, return 3 as the starting index. 86 | ``` 87 | 88 | 基于一个数学定理 89 | ``` 90 | 如果一个数组的总和非负,那么一定可以找到一个起始位置,从他开始绕数组一圈,累加和一直都是非负的``` 91 | 92 | 93 | 94 | 有了这个定理,判断到底是否存在这样的解非常容易,只需要把全部的油耗情况计算出来看看是否大于等于0即可。那么如何求开始位置在哪?注意到这样一个现象: 95 | 1. 假如从位置i开始,i+1,i+2...,一路开过来一路油箱都没有空。说明什么?说明从i到i+1,i+2,...肯定是正积累。 96 | 2. 现在突然发现开往位置j时油箱空了。这说明什么?说明从位置i开始没法走完全程(废话)。那么,我们要从位置i+1开始重新尝试吗?不需要!为什么?因为前面已经知道,位置i肯定是正积累,那么,如果从位置i+1开始走更加没法走完全程了,因为没有位置i的正积累了。同理,也不用从i+2,i+3,...开始尝试。所以我们可以放心地从位置j+1开始尝试。 97 | ``` 98 | 99 | ```java 100 | class Solution { 101 | public int canCompleteCircuit(int[] gas, int[] cost) { 102 | int start = 0; // 起始位置 103 | int remain = 0; // 当前剩余燃料 104 | int debt = 0; // 前面没能走完的路上欠的债 105 | for(int i = 0;i=0?start:-1; 114 | 115 | } 116 | } 117 | ``` -------------------------------------------------------------------------------- /doc/notes/algorithm(算法)/算法.md: -------------------------------------------------------------------------------- 1 | ![img](/Users/xiantang/project/Java-BackEnd-Notes/doc/images/4107856_1568009455024_C5529731D205FF0536BFD79DC2B77E2F.png) 2 | 3 | \2. 买苹果最少袋子数-贪心法 4 | 5 | ![img](/Users/xiantang/project/Java-BackEnd-Notes/doc/images/4107856_1568009458775_8644D040AB160A2A01503A66EF51DC85.png) 6 | 7 | \3. 线性排列正方形的最少涂染数-辅助数组 8 | 9 | ![img](/Users/xiantang/project/Java-BackEnd-Notes/doc/images/4107856_1568009463299_2CDA94D4E23904213327085490B646D8.png) 10 | 11 | \4. N阶方阵中最大正方形边长-辅助数组 12 | 13 | ![img](/Users/xiantang/project/Java-BackEnd-Notes/doc/images/4107856_1568009467459_74589865AF0C2B502DE066090FDB7282.png) 14 | 15 | \5. 指定概率数字生成函数-构造概率函数,数学题 16 | 17 | ![img](/Users/xiantang/project/Java-BackEnd-Notes/doc/images/4107856_1568009472158_1E574037FC5D7EA7D4FBBDBE3C4D392E.png) 18 | 19 | 6.给定非负整数n能形成的二叉树结构数目-左右子树加上根节点,递归或者动态规划 20 | 21 | 7.构成完整括号字符串的最少添加括号数-2个变量计数 22 | 23 | 8.差值为k的去重数字对-哈希 24 | 25 | 9.最大magic操作数-贪心 26 | 27 | 10.可以转换的不同字符串的个数-动态规划 28 | 29 | 11.括号序列的深度-动态规划 30 | 31 | 12.栈的升序排序-栈 32 | 33 | 13.青草游戏-打表 34 | 35 | 14.根节点到叶节点权值最大-树形dp 36 | 37 | 15.打包机器-贪心 38 | 39 | 16.zipzap打印矩阵-模拟 40 | 41 | 17.螺旋打印矩阵-模拟 42 | 43 | 18.顺时针选择矩阵-模拟 44 | 45 | 19.有序二维数组找书-模拟 46 | 47 | 20.拼接出长度n的最小操作数-分类讨论 48 | 49 | 21.找出现次数最多前k个字符串-堆 50 | 51 | 22.狗猫队列-队列哈希 52 | 53 | 23.返回栈中最小元素-栈 54 | 55 | 24.栈队列转换-栈、队列 56 | 57 | 25.动态规划空间压缩 58 | 59 | 26.容器灌水-栈 60 | 61 | 27.左右部分最大绝对值之差-队列 62 | 63 | 28.旋转词-kmp算法 64 | 65 | 29.附加题-斐波那契数列矩阵乘法 66 | 67 | 30.达标字符串数量-斐波那契数列 68 | 69 | 31.删除木棒数-贪心、斐波那契数列 70 | 71 | 32.调整数列两两相乘为4的倍数-思维题 72 | 73 | 33.判断字符串是否为整数-正则表达式 74 | 75 | 34.TopKRecord结构-背包 76 | 77 | 35.放进背包的零食种数-动态规划 78 | 79 | 36.牛牛找工作-贪心 80 | 81 | 37.画目录结构-字母多叉树 82 | 83 | 38.搜索二叉树转换有序双向列表-思维题 84 | 85 | 39.最大搜索二叉子树的节点个数-树形结构 86 | 87 | 40.返回后序遍历-递归 88 | 89 | 41.安置路灯-贪心,动态规划 90 | 91 | 42.帖子最高分数-动态规划 92 | 93 | 43.子矩阵的最大累计和-思维题 94 | 95 | 44.数字用中文表示-模拟 96 | 97 | 45.找到[1,n]中所有未出现在A中的整数-数组 98 | 99 | 46.神奇的数列-思维题 100 | 101 | 47.送C币-贪心 102 | 103 | 48.求完全二叉树节点的个数-递归 104 | 105 | 49.cc直播运营活动-bfs 106 | 107 | 50.最长递增子序列问题-动态规划 108 | 109 | 51.最大子数组异或和-动态规划 110 | 111 | 52.express组合成desired的方案数-区间动归 112 | 113 | 53.字典序问题-暴力 114 | 115 | 54.无重复字符子串中最长的长度-滑动窗口 116 | 117 | 55.最小编辑代价-动态规划 118 | 119 | 56.删字符-贪心 120 | 121 | 57.字符串变换-bfs 122 | 123 | 58.可变更缓存结构-哈希、双向链表 124 | 125 | 59.求一条直线最多能穿过多少个点-枚举 126 | 127 | 60.最少的跳跃次数跳到最后一个数-贪心 128 | 129 | 61.两个数相加和最大的前k个-思维题 130 | 131 | 62.数组分成4部分-二分答案 132 | 133 | 63.判断字符串是否为交错组成-动态规划 134 | 135 | 64.找丑数-模拟 136 | 137 | 65.需要排序的最短子数组长度-思维题 138 | 139 | 66.最小不可组成和-动态规划 140 | 141 | 67.组成区间缺少的数-动态规划 142 | 143 | 68.返回在[0,1)范围上的数,[0,x)区间上的数出现的概率为x^k-随机分析 144 | 145 | 69.gcd图联通区域-并查集 146 | 147 | 70.求最少添加多少个字符使得包含两个str且开始的位置不能一样-next数组 148 | 149 | 71.判断T1的某棵子树和T2相等-递归 150 | 151 | 72.根据压缩字符串还原出原始字符串-模拟 152 | 153 | 73.拼接完美矩形-模拟代码 154 | 155 | 74.最长可整合数组-哈希 156 | 157 | 75.添加最少字符使字符串整体都是回文字符串-动态规划 158 | 159 | 76.一种消息接收并打印的结构设计-链表 160 | 161 | 77.给定k个有序链表merge成一个有序的链表-链表 162 | 163 | 78.判断点是否在矩形和三角形内-计算几何 164 | 165 | 79.找到数组中未出现的最小正整数-思维题 166 | 167 | 80.添加最少字符使字符串整体都是回文字符串-动态规划 168 | 169 | 81.打印有序数组中所有累加和为aim的二元、三元组-思维题 170 | 171 | 82.在一个有序的旋转数组中,查找最小值-二分 172 | 173 | 83.矩阵最长的递增路径-动态规划 174 | 175 | 84.最大子矩阵累加和-动态规划 176 | 177 | 85.克隆图-递归 178 | 179 | 86.图中找word-搜索 180 | 181 | 87.二叉树的最小高度-递归 182 | 183 | 88.买股票-贪心 184 | 185 | 89.买股票2-贪心 186 | 187 | 90.买股票3-动态规划 188 | 189 | 91.在一个有序的旋转数组中,查找给定值-二分 190 | 191 | 92.两个字符串子序列不同的个数-动态规划 192 | 193 | 93.返回字符串得到整数的所以不同方法-搜索 194 | 195 | 94.打印二叉树的边界节点-搜索 196 | 197 | 95.在单链表和双链表中删除倒数第K个节点-链表 198 | 199 | 96.反转部分单向链表-链表 200 | 201 | 97.二叉树的按层打印与ZigZag打印-bfs 202 | 203 | 98.将单链表的每K个节点之间逆序-链表 204 | 205 | 99.找到指定的新类型字符-思维题模拟字符串 206 | 207 | 100.龙与地下城游戏问题-动态规划 208 | 209 | 101.合并区间-模拟 210 | 211 | 102.轨迹碰撞-模拟 212 | 213 | 103.单词拆分-字符串匹配 214 | 215 | 104.求二叉树上最大的路径累加和-树形dp 216 | 217 | 105.数组累乘-思维题 218 | 219 | 106.找数-异或 220 | 221 | 107.根据后序遍历的结果生成整棵树-递归 222 | 223 | 108.区间操作器-线段树 -------------------------------------------------------------------------------- /doc/notes/algorithm(算法)/leetCode TODO.md: -------------------------------------------------------------------------------- 1 | ## 链表 2 | * - [x] 链表的必备知识要点(包括基础知识、刷题中使用的STL等知识) 3 | * - [x] 链表逆序(LeetCode 92,206. Reverse Linked List 1,2) 4 | * - [x] 求两个链表的交点(LeetCode 160. Intersection of Two Linked Lists) 5 | * - [x] 链表的节点交换(LeetCode 24. Swap Nodes in Pairs) 6 | * - [x] 链表求环(LeetCode 141,142. Linked List Cycle 1,2) 7 | * - [x] 链表重新构造(LeetCode 86. Partition List) 8 | * - [x] 复杂的链表复制(LeetCode 138. Copy List with Random Pointer) 9 | * - [x] 排序链表合并(2个与多个) (LeetCode 21,23 Merge Two(k) Sorted ListsLeetCode) 10 | 11 | 12 | ## 栈、队列、堆 13 | * - [x] 栈、队列知识要点与实现(数组、链表) 14 | * - [x] 使用队列实现栈(LeetCode 232. Implement Queue using Stacks) 15 | * - [x] 使用栈实现队列(LeetCode 225. Implement Stack using Queues) 16 | * - [x] 包含min函数的栈(LeetCode 155. Min Stack) 17 | * - [ ] 简单的计算器(栈的应用)( LeetCode 224. Basic Calculator) 不会做 18 | * - [x] 堆(优先级队列)知识要点与实现 19 | * - [x] 数组中第K大的数(堆的应用) (LeetCode 215. Kth Largest Element in an Array) 20 | * - [x] 寻找中位数(堆的应用)( LeetCode 295 Find Median from Data Stream) 21 | 22 | 23 | ## 贪心 24 | * - [x] 贪心算法知识要点,刷题必备的STL知识 25 | * - [x] 贪心题目1(LeetCode 455. Assign Cookies) 26 | * - [x] 贪心题目2(LeetCode 402. Remove K Digits) 27 | * - [x] 贪心题目3(LeetCode 134. Gas Station) 28 | * - [x] 贪心题目4(LeetCode 135. Candy) 29 | * - [x] 贪心题目5(LeetCode 502. IPO) 30 | * - [x] 贪心题目6(LeetCode 321. Create Maximum Number) 31 | * - [ ] 贪心题目7(codeforces 582A GCD Table) 32 | 33 | 34 | ## 递归、分制、回溯 35 | * - [x] 递归的知识要点,回溯算法 36 | * - [x] 生成组合数(LeetCode 39. Combination Sum, LeetCode 40. Combination Sum II) 37 | * - [x] 生成排列数(LeetCode 46. Permutations, LeetCode 47. Permutations II) 38 | * - [x] N皇后问题(LeetCode 51. N-Queens, LeetCode 52. N-Queens II) 39 | * - [x] 分制算法知识要点 40 | * - [x] 快速排序算法与经典实现 41 | * - [x] 不同的加括号方法(LeetCode 241. Different Ways to Add Parentheses) 42 | * - [ ] 两个数组的中位数(LeetCode 4. Median of Two Sorted Arrays) 43 | 44 | 45 | ## 树与图 46 | * - [x] 树与图的数据结构与基本算法 47 | * - [x] 树遍历的回调函数实现,并使用自动机概念实现非递归树前、中、后遍历 48 | * - [x] 树与链表的转换(LeetCode 114. Flatten Binary Tree to Linked List) 49 | * - [x] 最近的公共祖先(LeetCode 236. Lowest Common Ancestor of a Binary Tree) 50 | * - [x] 树的层次遍历应用(LeetCode 199. Binary Tree Right Side View) 51 | * - [x] 树的改造(LeetCode 117. Populating Next Right Pointers in Each Node 1,2) 52 | * - [x] 图的复制(LeetCode 133. Clone Graph) 53 | * - [x] 图的搜索与应用(LeetCode 207.Course Schedule) 54 | 55 | ## 二分查找、二叉排序树、位运算的应用 56 | * - [x] 二分查找、二叉排序树的知识要点 57 | * - [x] 数组的二分查找(LeetCode 33,81 Search in Rotated Sorted Array 1,2) 58 | * - [x] 区间二分查找(LeetCode 34. Search for a Range) 59 | * - [x] 排序链表转换为二叉排序树(LeetCode 109. Convert Sorted List to B- Search Tree) 60 | * - [x] 二叉排序树的遍历与改造(LeetCode 538 Convert BST to Greater Tree) 61 | * - [x] 二叉排序树中的第K大的数(LeetCode 230. Kth Smallest Element in a BST) 62 | * - [x] 位运算的知识要点 63 | * - [x] 使用位运算表示集合(LeetCode 78. Subsets) 64 | * - [x] 位运算应用题目(LeetCode 136,137,260. Single Number1,2,3) 65 | 66 | ## 哈希表与字符串 67 | * - [x] 哈希表与字符串知识要点 68 | * - [x] 哈希题目 (LeetCode 290. Word Pattern) 69 | * - [x] 哈希与字符串综合 (LeetCode 3.Longest Substring Without Repeating Characters) 70 | * - [ ] 哈希与字符串综合 (LeetCode 76. Minimum Window Substring) 71 | * - [ ] 哈希与字符串综合 (LeetCode 30. Substring with Concatenation of All Words) 72 | * - [x] 字符串题目 (LeetCode 459. Repeated Substring Pattern) 73 | * - [ ] 字符串题目 (LeetCode 468. Validate IP Address) 74 | 75 | ## 搜索 76 | * - [x] 深度优先搜索与广度优先搜索算法 77 | * - [x] 深搜题目 (LeetCode 200. Number of Islands) 78 | * - [x] 深搜题目 (LeetCode 473. Matchsticks to Square) 79 | * - [x] 深搜题目 (LeetCode 491. Increasing Subsequences) 80 | * - [x] 广搜题目 (LeetCode 126,127 Word Ladder 1,2) 81 | * - [x] 广搜题目 (LeetCode 417. Pacific Atlantic Water Flow) 82 | * - [x] 广搜题目 (LeetCode 407. Trapping Rain Water II) 83 | 84 | ## 动态规划 85 | * - [x] 动态规划知识要点 86 | * - [x] 动态规划题目1(LeetCode 120. Triangle) 87 | * - [x] 动态规划题目2(LeetCode 53. Maximum Subarray) 88 | * - [x] 动态规划题目3(LeetCode 198. House Robber 1,2) 89 | * - [x] 动态规划题目3(LeetCode 213. House Robber 2) 90 | * - [x] 动态规划题目4(LeetCode 322. Coin Change) 91 | * - [ ] 动态规划题目5(LeetCode 72. Edit Distance) 92 | * - [ ] 动态规划题目6(LeetCode 174. Dungeon Game) 93 | * - [ ] 动态规划题目7(codeforces 711C Coloring Trees) 94 | 95 | ## 复杂数据结构 96 | * - [ ] Trie树的构造与基本算法 97 | * - [ ] Trie树的构造 (LeetCode 208. Implement Trie (Prefix Tree)) 98 | * - [ ] Trie树的应用 (LeetCode 212. Word Search II) 99 | * - [ ] 并查集的基本算法 100 | * - [ ] 并查集的应用 (LeetCode 547. Friend Circles) 101 | * - [ ] 线段树与树状数组 102 | * - [ ] 线段树与树状数组的应用(LeetCode 307. Range Sum Query – Mutable) -------------------------------------------------------------------------------- /doc/notes/translate(翻译作品)/equals() 和 hashCode() 方法在Java中的关系.md: -------------------------------------------------------------------------------- 1 | Java.lang.object 定义了两个非常重要的方法: 2 | 3 | * public boolean equals(Object obj) 4 | * public int hashCode() 5 | 6 | 7 | ## equals() 方法 8 | 9 | 在Java 中 equals()是用来比较两个对象是否相等。主要分为两个方面的比较: 10 | 11 | * **浅比较(Shallow comparison)**:在Java.lang.Object 类中默认的实现是简单的比较两个引用(假设是x和y)是否指向同样的对象。由于Object类没有定义其状态的数据成员,所以也称之为浅比较(Shallow comparison)。 12 | * **深比较(Deep Comparison)**:假设一个类提供了拥有对equals()方法的自己的实现,目的去比较具有w.r.t状态的对象。意思是对象中的数据成员(例如:域)将会被比较。基于数据成员的比较方式叫做深比较(Deep Comparison)。 13 | 14 | 语法: 15 | 16 | ```java 17 | public boolean equals (Object obj) 18 | 19 | // This method checks if some other Object 20 | // passed to it as an argument is equal to 21 | // the Object on which it is invoked. 22 | //此方法检查是否有其他Object 23 | //作为参数传递给它等于 24 | //调用它的Object。 25 | ``` 26 | 27 | **Object类中一些关于equals()的原则**:如果某个其他对象等于给定对象,则它遵循以下规则: 28 | 29 | * 自反性:对于任何引用a,`a.equals(a)`应该返回true。 30 | * 对称性:对于任何引用a和b,如果`a.equals(b)`返回true,那么`b.equals(a)`必须返回true。 31 | * 传递性:对于任何引用a,b和c,如果`a.equals(b)`返回true, 并且`b.equals(c)`返回true,则`a.equals(c)`应该返回true。 32 | * 一致性:对于任何应用a和b,多次调用`a.equals(b)`始终返回true或始终返回false,前提是在没有修改对象`equals`比较中使用的信息。 33 | 34 | 注:对于任何非空的引用a,` a.equals(null) `应该返回false。 35 | 36 | 37 | ```Java 38 | class Geek 39 | { 40 | 41 | public String name; 42 | public int id; 43 | 44 | Geek(String name, int id) 45 | { 46 | 47 | this.name = name; 48 | this.id = id; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object obj) 53 | { 54 | // 是否引用都指向同一个对象 55 | // checking if both the object references are 56 | // referring to the same object. 57 | if(this == obj) 58 | return true; 59 | // 比较当前对象和传入的参数的类对象是否相同 60 | // it checks if the argument is of the 61 | // type Geek by comparing the classes 62 | // of the passed argument and this object. 63 | // if(!(obj instanceof Geek)) return false; ---> avoid. 64 | if(obj == null || obj.getClass()!= this.getClass()) 65 | return false; 66 | // 向下转型 67 | // type casting of the argument. 68 | Geek geek = (Geek) obj; 69 | 70 | // 比较成员变量 71 | // comparing the state of argument with 72 | // the state of 'this' Object. 73 | return (geek.name == this.name && geek.id == this.id); 74 | } 75 | 76 | @Override 77 | public int hashCode() 78 | { 79 | // 我们返回Geek_id作为hashcode 80 | // 我们可以计算或者使用对象内存地址的值 81 | // 这取决于你如何实现hashCode()方法。 82 | // We are returning the Geek_id 83 | // as a hashcode value. 84 | // we can also return some 85 | // other calculated value or may 86 | // be memory address of the 87 | // Object on which it is invoked. 88 | // it depends on how you implement 89 | // hashCode() method. 90 | return this.id; 91 | } 92 | 93 | } 94 | 95 | //Driver code 96 | class GFG 97 | { 98 | 99 | public static void main (String[] args) 100 | { 101 | 102 | // creating the Objects of Geek class. 103 | Geek g1 = new Geek("aa", 1); 104 | Geek g2 = new Geek("aa", 1); 105 | // 比较上面创建的对象 106 | // comparing above created Objects. 107 | if(g1.hashCode() == g2.hashCode()) 108 | { 109 | 110 | if(g1.equals(g2)) 111 | System.out.println("Both Objects are equal. "); 112 | else 113 | System.out.println("Both Objects are not equal. "); 114 | 115 | } 116 | else 117 | System.out.println("Both Objects are not equal. "); 118 | } 119 | } 120 | 121 | ``` 122 | 123 | 输出: 124 | ``` 125 | Both Objects are equal. 126 | ``` 127 | 128 | 首先我们比较hashCode在两个对象上(g1和g2)如果hashCode产生自两个对象并不意味着这两个对象相同,两个不同的对象的hashCode也是可以相同的。而且,如果他们拥有相同的id(在这种情况下)。那么我们将比较这两个对象w.r.t的状态。如果两个对象具有相同的状态,则他们相等,否则不相等。 129 | 130 | 在上面的例子中看到这一行: 131 | 132 | ``` 133 | // if(!(obj instanceof Geek)) return false;--> avoid.-->(a) 134 | ``` 135 | 136 | 我们使用下面一行来代替上面这一行: 137 | ```java 138 | if(obj == null || obj.getClass()!= this.getClass()) return false; --->(y) 139 | ``` 140 | 141 | 原因:引用obj也可以引用Geek对象的子类,在Line(b)中传入的对象是Geek的子类的对象的话,就会返回false,但是在Line(a)中却会返回true。 142 | 143 | ## hashCode() method 144 | 145 | 146 | 它将哈希码值作为整数返回。 Hashcode值主要用于基于散列的集合,如`HashMap`,`HashSet`,`HashTable` ... .etc。必须在覆盖`equals()`方法的每个类中重写此方法。 147 | 148 | 语法: 149 | 150 | ```java 151 | public int hashCode() 152 | 153 | // This method returns the hash code value 154 | // for the object on which this method is invoked. 155 | // 当这个方法被调用时候返回hashcode 156 | ``` 157 | 158 | **普遍的hashCode规定有**: 159 | * 在代码的运行期时,多次调用hashCode()在同一个对象然后必须返回一致的整数值。如果对象没有在`equals(ojb)`比较中有成员变量被修改,调用后返回的值都一致。 160 | * 如果两个对象相等,则根据`equals(Object)`方法,`hashCode()`方法必须在两个对象中的每一个上生成相同的Integer。 161 | * 如果两个对象不相等,则根据`equals(Object)`方法,`hashCode()`方法在两个对象中的每一个上生成的Integer值不必是不同的。它可以是相同的,但是对于两个不同的对象,通过hashCode产生不同的值对于提高基于散列的集合(如HashMap,HashTable等)的性能会更好。 162 | 163 | -------------------------------------------------------------------------------- /doc/notes/database(数据库)/redis/redis.md: -------------------------------------------------------------------------------- 1 | ![8647D9F7-BE84-40EC-B4E1-D3773F741FA7.png](blob:file:///9340b11f-01ca-471a-8284-16374d0413f2) 2 | 3 | ## 安装redis 4 | 5 | 创建redis目录 6 | `mkdir redis` 7 | 8 | 安装wget 9 | `yum install -y wget` 10 | 11 | 12 | 13 | ## 设置登陆密码 14 | 15 | 这是修改redis的配置文件 16 | `vim /etc/redis/redis.conf` 17 | 18 | 找到`requirepass` 19 | 修改密码。 20 | 21 | 重启`redis` 22 | 23 | `/etc/init.d/redis-server restart` 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ## scrapy爬虫报错 32 | 33 | ```python 34 | 2018-12-23 14:03:12 [twisted] CRITICAL: Unhandled Error 35 | Traceback (most recent call last): 36 | File "/home/ubuntu/.local/lib/python3.5/site-packages/scrapy/commands/crawl.py", line 58, in run 37 | self.crawler_process.start() 38 | File "/home/ubuntu/.local/lib/python3.5/site-packages/scrapy/crawler.py", line 291, in start 39 | reactor.run(installSignalHandlers=False) # blocking call 40 | File "/home/ubuntu/.local/lib/python3.5/site-packages/twisted/internet/base.py", line 1267, in run 41 | self.mainLoop() 42 | File "/home/ubuntu/.local/lib/python3.5/site-packages/twisted/internet/base.py", line 1276, in mainLoop 43 | self.runUntilCurrent() 44 | --- --- 45 | File "/home/ubuntu/.local/lib/python3.5/site-packages/twisted/internet/base.py", line 902, in runUntilCurrent 46 | call.func(*call.args, **call.kw) 47 | File "/home/ubuntu/.local/lib/python3.5/site-packages/scrapy/utils/reactor.py", line 41, in __call__ 48 | return self._func(*self._a, **self._kw) 49 | File "/home/ubuntu/.local/lib/python3.5/site-packages/scrapy/core/engine.py", line 122, in _next_request 50 | if not self._next_request_from_scheduler(spider): 51 | File "/home/ubuntu/.local/lib/python3.5/site-packages/scrapy/core/engine.py", line 149, in _next_request_from_scheduler 52 | request = slot.scheduler.next_request() 53 | File "/home/ubuntu/.local/lib/python3.5/site-packages/scrapy_redis/scheduler.py", line 172, in next_request 54 | request = self.queue.pop(block_pop_timeout) 55 | File "/home/ubuntu/.local/lib/python3.5/site-packages/scrapy_redis/queue.py", line 115, in pop 56 | results, count = pipe.execute() 57 | File "/home/ubuntu/.local/lib/python3.5/site-packages/redis/client.py", line 3443, in execute 58 | return execute(conn, stack, raise_on_error) 59 | File "/home/ubuntu/.local/lib/python3.5/site-packages/redis/client.py", line 3339, in _execute_transaction 60 | self.immediate_execute_command('DISCARD') 61 | File "/home/ubuntu/.local/lib/python3.5/site-packages/redis/client.py", line 3275, in immediate_execute_command 62 | return self.parse_response(conn, command_name, **options) 63 | File "/home/ubuntu/.local/lib/python3.5/site-packages/redis/client.py", line 3402, in parse_response 64 | self, connection, command_name, **options) 65 | File "/home/ubuntu/.local/lib/python3.5/site-packages/redis/client.py", line 768, in parse_response 66 | response = connection.read_response() 67 | File "/home/ubuntu/.local/lib/python3.5/site-packages/redis/connection.py", line 638, in read_response 68 | raise response 69 | redis.exceptions.ResponseError: DISCARD without MULTI 70 | 71 | ``` 72 | 73 | 查看redis的log 74 | 75 | `cat /etc/redis/redis.conf` 76 | 77 | 找到日志的位置 78 | 79 | `tail -100 /var/log/redis/redis-server.log` 80 | 81 | 82 | ```log 83 | 3655:M 23 Dec 14:22:04.093 * 1 changes in 900 seconds. Saving... 84 | 3655:M 23 Dec 14:22:04.093 # Can't save in background: fork: Cannot allocate memory 85 | 3655:M 23 Dec 14:22:10.005 * 1 changes in 900 seconds. Saving... 86 | 3655:M 23 Dec 14:22:10.005 # Can't save in background: fork: Cannot allocate memory 87 | 3655:M 23 Dec 14:22:16.018 * 1 changes in 900 seconds. Saving... 88 | 3655:M 23 Dec 14:22:16.018 # Can't save in background: fork: Cannot allocate memory 89 | 3655:M 23 Dec 14:22:22.030 * 1 changes in 900 seconds. Saving... 90 | 3655:M 23 Dec 14:22:22.031 # Can't save in background: fork: Cannot allocate memory 91 | 3655:M 23 Dec 14:22:28.041 * 1 changes in 900 seconds. Saving... 92 | 3655:M 23 Dec 14:22:28.041 # Can't save in background: fork: Cannot allocate memory 93 | 3655:M 23 Dec 14:22:34.059 * 1 changes in 900 seconds. Saving... 94 | 3655:M 23 Dec 14:22:34.059 # Can't save in background: fork: Cannot allocate memory 95 | 3655:M 23 Dec 14:22:40.072 * 1 changes in 900 seconds. Saving... 96 | 3655:M 23 Dec 14:22:40.073 # Can't save in background: fork: Cannot allocate memory 97 | 98 | ``` 99 | 100 | 原因: 101 | 102 | * 在小内存进程上做fork 不需要太多资源,当进程的内存以G为单位 103 | fork 就很奢侈了 104 | * 所以一直cannot allocate memory 105 | 106 | 解决方案: 107 | 108 | 直接修改内核参数 `vm.overcommit_memory = 1` 109 | linux 会根据参数来决定是否放行 110 | 111 | 112 | ```bash 113 | sudo echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf sudo sysctl -p 114 | ``` 115 | 116 | 内核分配参数 117 | 118 | 0 表示检查是否有足够的可用内存供应用进程使用; 119 | 1 表示内核允许分配所有的物理内存,而不管当前的内存状态如何 120 | 121 | 122 | 123 | Redis 简单动态字符串实现 124 | 125 | 126 | 127 | 不仅仅需要字面量,需要可以修改的字符串的值 128 | 129 | 在底层是SDS 实现 130 | 131 | 执行 SET msg "hello world" 132 | 133 | 键值都是SDS 134 | 135 | 136 | 137 | ![屏幕快照 2019-11-29 下午2.03.09](/Users/xiantang/Desktop/屏幕快照 2019-11-29 下午2.03.09.png) 138 | 139 | ![屏幕快照 2019-11-29 下午2.14.03](/Users/xiantang/Desktop/屏幕快照 2019-11-29 下午2.14.03.png) 140 | 141 |   142 | 143 | 简单看了下 set的底层实现 set 其实是value 为空的hashtable 144 | 145 | 之前set比 string占用小应该是 string 设置进去的时候我将值设置为了 1 所以测出来set 比 string 小 4M 其实在这种情况下两者的差异并不大 然后还有一点 set 如果全是数字的话 采用的会是 inset ,并且会根据插入的元素进行升级 升级为32 位或者 64位,可以达到解决空间的效果。 146 | 147 | 用的拉链法 +  头插 148 | 149 | load_factor = ht[0].used / ht[0].size 150 | 151 | 152 | 153 | 当负载因子小于0.1的时候程序自动对hash表进行收缩 154 | 155 | 156 | 157 | 渐进式rehash: 158 | 159 | rehash不是一次性的和集中性的,如果键值对有很大的量,一瞬间rehash的话会导致服务器宕机 160 | 161 | 采用一种分而治之的方式进行操作,每次增删改查在完成对应工作后,都会对一个dictEntry的所有键值对进行rehash。将集中式的操作转换为了独立的可拆分的操作,并且在rehash的过程中,会从两个dict中进行查询。 -------------------------------------------------------------------------------- /doc/notes/database(数据库)/mysql/index.md: -------------------------------------------------------------------------------- 1 | ## 索引的类型: 2 | 3 | ### B-Tree 索引 4 | InnoDB 使用的是B+Tree 5 | ![img](../../../images/8394323_1307440587b6WG.jpg) 6 | 7 | 根节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下查找。通过要查找的值来找到合适的指针进入下层节点。 8 | 9 | 假设有如下数据表 10 | 11 | ```sql 12 | create table people( 13 | last_name varchar(50) not null, 14 | first_name varchar(50) not null, 15 | dob date not null, 16 | gender enum('m','f') not null, 17 | key(last_name,first_name,dob) 18 | ); 19 | ``` 20 | 21 | 对于表中的每一行数据,索引中包含了last_name,first_name 和 dob 列的值。 显示了该索引是如何组织数据存储的。 22 | 23 | ![](muti.png) 24 | 25 | 有效使用索引: 26 | * 全值匹配 27 | * 匹配最左前缀 28 | * 匹配列前缀 29 | * 匹配范围值 30 | * 精确匹配某一列并范围匹配另外一列 31 | * 值访问索引 32 | 33 | B-Tree 索引的限制: 34 | 35 | * 如果不是按照索引的最左侧开始查找,就无法使用索引。 36 | * 不能跳过索引中的列,如果要查找姓名为 A 生日在 B 的人是只能使用索引的第一列。 37 | 38 | 39 | ### B-树 40 | 41 | * 内部节点:含有与页相关联的页的副本 42 | * 外部节点:含有指向实际数据的引用 43 | * 哨兵键:小于其他所有键,一开始B-树只含有 44 | 一个根节点,节点初始化出的就是哨兵节点 45 | 46 | #### 查找和插入 47 | 48 | 查找:在可能含有被查找键的唯一子树中进行一次递归的 49 | 搜索 50 | ![](https://img-blog.csdn.net/20170910224108969?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjEyNDQzOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 51 | 插入: 52 | 如果被插入的节点变成一个溢出的节点 53 | 递归调用不断向上调用分裂溢出的节点 54 | ![](https://img-blog.csdn.net/20170910224922359?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjEyNDQzOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 55 | 56 | 57 | ## 为什么使用B-Tree / B+Tree 58 | 59 | 主要和硬盘的存取原理有关。 60 | 硬盘不是按需读取的,每次读取都会预读一些。 61 | ``` 62 | 当一个数据被用到的时候,其附近的数据也会通常马上使用程序运行期间所需要的数据通常比较集中 63 | ``` 64 | 65 | 一般预读的长度为页的整数倍 66 | 67 | 为什么使用B-Tree/B+Tree 不用红黑树 68 | 出度大,并且高度小(通常不会超过3) 69 | 70 | 为什么使用 B+树 71 | * 适合外部存储,内部没有data域,一个索引节点可以存储多个节点,一个索引节点可以存储大量分支,每个节点能够索引的范围更大更精确,也意为着B+树单次IO信息量大于B- 树 I/O效率高 72 | * B+树查询必须找到叶子节点,B树只要匹配到就可以不管元素位置,而且更加稳定(并不慢) 73 | * B+树只要顺序遍历叶子节点,B树却需要重复的中序遍历。 74 | 75 | 76 | ## 数据库使用乐观锁 77 | 比较 交换 78 | 79 | 80 | 1.使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。用下面的一张图来说明: 81 | 82 | ![](http://dl.iteye.com/upload/picture/pic/125402/22a9518f-e355-315f-8d66-d91af4fda723.jpg) 83 | 84 | 85 | 使用举例:以MySQL InnoDB为例 86 | 87 | 还是拿之前的实例来举:商品goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品status为1。假设商品的id为1。 88 | 89 | 90 | 91 | 下单操作包括3步骤: 92 | 93 | 1.查询出商品信息 94 | ```sql 95 | select (status,status,version) from t_goods where id=#{id} 96 | ``` 97 | 2.根据商品信息生成订单 98 | 99 | 3.修改商品status为2 100 | ```sql 101 | update t_goods 102 | 103 | set status=2,version=version+1 104 | 105 | where id=#{id} and version=#{version}; 106 | ``` 107 | 108 | 109 | 那么为了使用乐观锁,我们首先修改t_goods表,增加一个version字段,数据默认version值为1。 110 | 111 | t_goods表初始数据如下: 112 | 113 | ```sql 114 | select * from t_goods; 115 | +----+--------+------+---------+ 116 | | id | status | name | version | 117 | +----+--------+------+---------+ 118 | | 1 | 1 | 道具 | 1 | 119 | | 2 | 2 | 装备 | 2 | 120 | +----+--------+------+---------+ 121 | 2 rows in set 122 | ``` 123 | 124 | 125 | Goods实体类: 126 | 127 | ```java 128 | /** 129 | * ClassName: Goods
130 | * Function: 商品实体.
131 | * date: 2013-5-8 上午09:16:19
132 | * @author chenzhou1025@126.com 133 | */ 134 | public class Goods implements Serializable { 135 | 136 | /** 137 | * serialVersionUID:序列化ID. 138 | */ 139 | private static final long serialVersionUID = 6803791908148880587L; 140 | 141 | /** 142 | * id:主键id. 143 | */ 144 | private int id; 145 | 146 | /** 147 | * status:商品状态:1未下单、2已下单. 148 | */ 149 | private int status; 150 | 151 | /** 152 | * name:商品名称. 153 | */ 154 | private String name; 155 | 156 | /** 157 | * version:商品数据版本号. 158 | */ 159 | private int version; 160 | 161 | @Override 162 | public String toString(){ 163 | return "good id:"+id+",goods status:"+status+",goods name:"+name+",goods version:"+version; 164 | } 165 | 166 | //setter and getter 167 | 168 | } 169 | ``` 170 | 171 | Dao 172 | 173 | ```java 174 | @Mapper 175 | public interface GoodsDao { 176 | @Select("select ID,status,name,version from t_goods where id=#{id}") 177 | Goods getGood(@Param("id")int id); 178 | 179 | @Update(" update t_goods \n" + 180 | " set status=#{status},name=#{name},version=version+1 \n" + 181 | " where id=#{id} and version=#{version}") 182 | int update(Goods goods); 183 | } 184 | 185 | ``` 186 | 187 | java 代码 188 | 189 | ```java 190 | @Test 191 | public void goodsDaoTest(){ 192 | int goodsId = 1; 193 | //根据相同的id查询出商品信息,赋给2个对象 194 | Goods goods1 = this.goodsDao.getGoodsById(goodsId); 195 | Goods goods2 = this.goodsDao.getGoodsById(goodsId); 196 | 197 | //打印当前商品信息 198 | System.out.println(goods1); 199 | System.out.println(goods2); 200 | 201 | //更新商品信息1 202 | goods1.setStatus(2);//修改status为2 203 | int updateResult1 = this.goodsDao.updateGoodsUseCAS(goods1); 204 | System.out.println("修改商品信息1"+(updateResult1==1?"成功":"失败")); 205 | 206 | //更新商品信息2 207 | goods1.setStatus(2);//修改status为2 208 | int updateResult2 = this.goodsDao.updateGoodsUseCAS(goods1); 209 | System.out.println("修改商品信息2"+(updateResult2==1?"成功":"失败")); 210 | } 211 | ``` 212 | 查出同一版本的数据,赋值给不同对象先对good1进行更新操作,执行成功,将version++。然后修改good2 这时候去比较version java对象的version 还是1 但是数据库的值已经是2了 所以就无法匹配了。 213 | 214 | 1. 按自然语言搜索模式查询 215 | `SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('关键词' IN NATURAL LANGUAGE MODE);` -------------------------------------------------------------------------------- /doc/notes/translate(翻译作品)/sdk.md: -------------------------------------------------------------------------------- 1 | # GrowingIO Marketing API Java Library 2 | 3 | ## 概述 4 | 5 | GrowingIO Marketing API 的 Java 版本封装库。 6 | 7 | 对应的 REST API 文档:[REST API - Push](https://shimo.im/docs/rvKhdc3wDkhxRt8Y/read). 8 | 9 | ## 安装 10 | 11 | ### maven 方式 12 | 将下边的依赖条件放到你项目的 maven pom.xml 文件里。 13 | 14 | ```xml 15 | 16 | com.growingio 17 | marketing-api-java-client 18 | 1.0-SNAPSHOT 19 | 20 | ``` 21 | 22 | ### 样例 23 | 24 | 25 | #### 推送 API 26 | * 构建推送对象:所有平台,推送目标是别名为 "alias1",通知内容为 ALERT。 27 | 构建 `PushMessage`: 28 | 29 | ```java 30 | // 需要替换成使用者的自己的变量 31 | String clientId = "clientId"; 32 | String secret = "secret"; 33 | String projectUid = "projectUid"; 34 | String ai = "ai"; 35 | 36 | PushMessageClient client = PushMessageClient.getInstance(clientId, secret, projectUid, ai); 37 | 38 | Options options = Options.newBuilder().setApnsProduction(true).build(); 39 | PushNotification notification = 40 | PushNotification.newBuilder() 41 | .setTitle("推送标题") 42 | .setAlert("推送内容") 43 | .setActionType("openApp") 44 | .setActionTarget("com.hello.world") 45 | .build(); 46 | 47 | PushMessage message = 48 | PushMessage.newBuilder() 49 | .setCid(UUID.randomUUID().toString()) 50 | .setName("测试名字"+System.currentTimeMillis()) 51 | .setPackageName("com.growingio.giodemo") 52 | .addAllAudience(Arrays.asList("alias1")) 53 | .setNotification(notification) 54 | .setOptions(options) 55 | .build(); 56 | 57 | ``` 58 | 59 | 推送 `PushMessage`: 60 | ```java 61 | try { 62 | HttpResponse response = client.send(message); 63 | if (response.isSuccess()) { 64 | LOG.info("Send push message successful!"); 65 | } 66 | LOG.info("code: {}, body: {}", response.getCode(), response.getBody()); 67 | assertTrue("", response.isSuccess()); 68 | 69 | } catch (Exception e) { 70 | LOG.error(e.getLocalizedMessage(), e); 71 | } 72 | ``` 73 | 74 | 75 | #### 弹窗 76 | 77 | * 构建弹窗对象:推送目标是别名为 "alias2",通知内容为 ALERT,消息素材 "https://xxxxxxxx/1130img.jpeg"。 78 | 79 | ```java 80 | // 创建targets 81 | HashMap parameter1 = new HashMap(); 82 | parameter1.put("key1", "value1"); 83 | parameter1.put("key2", "value2"); 84 | HashMap parameter2 = new HashMap(); 85 | parameter2.put("key1", "value1"); 86 | parameter2.put("key2", "value2"); 87 | Target target1 = Target.newBuilder() 88 | .setProductId("xxxx") 89 | .setType("openUrl") 90 | .setUrl("XxxActivity") 91 | .putAllParameter(parameter1) 92 | .build(); 93 | List targets = new ArrayList(); 94 | Target target2 = Target.newBuilder() 95 | .setProductId("xxxx") 96 | .setType("openUrl") 97 | .setUrl("XxxActivity") 98 | .putAllParameter(parameter2) 99 | .build(); 100 | targets.add(target1); 101 | targets.add(target2); 102 | 103 | 104 | // 根据 targets 创建 Rule 105 | Rule rule = Rule.newBuilder() 106 | .setAction("xxxOpen") 107 | .setLimit(2) 108 | .addAllTargets(targets) 109 | .setStartAt(1575092361116L) 110 | .setEndAt(1575095961116L) 111 | .setTriggerCd(86400L) 112 | .build(); 113 | 114 | // 根据 rule 创建 InAppMessage 115 | InAppMessage message = InAppMessage.newBuilder() 116 | .setName("testest") 117 | .setAudience("alias2") 118 | .setRule(rule) 119 | .setContent("https://xxxxxxxx/1130img.jpeg") 120 | .build(); 121 | ``` 122 | 123 | * 创建弹窗 124 | 125 | ```java 126 | InAppMessageClient client = InAppMessageClient.getInstance(clientId, secret, projectUid, ai); 127 | HttpResponse response = client.send(message); 128 | if (response.isSuccess()) { 129 | LOG.info("Send push message successful!"); 130 | } 131 | LOG.info("code: {}, body: {}", response.getCode(), response.getBody()); 132 | ``` 133 | 134 | * 更新弹窗 需要提供指定的messageId 135 | 136 | ```java 137 | InAppMessageClient client = InAppMessageClient.getInstance(clientId, secret, projectUid, ai); 138 | HttpResponse response = client.update(messageId,message); 139 | if (response.isSuccess()) { 140 | LOG.info("Send push message successful!"); 141 | } 142 | LOG.info("code: {}, body: {}", response.getCode(), response.getBody()); 143 | assertTrue("", response.isSuccess()); 144 | ``` 145 | 146 | * 删除弹窗 只需要提供指定的messageId 147 | 148 | ```java 149 | InAppMessageClient client = InAppMessageClient.getInstance(clientId, secret, projectUid, ai); 150 | HttpResponse response = client.delete(messageId); 151 | if (response.isSuccess()) { 152 | LOG.info("Send push message successful!"); 153 | } 154 | LOG.info("code: {}, body: {}", response.getCode(), response.getBody()); 155 | assertTrue("", response.isNoContent()); 156 | ``` 157 | 158 | * 检索弹窗 根据 projectUid 来查询该项目下的所有弹窗 159 | 160 | ```java 161 | InAppMessageClient client = InAppMessageClient.getInstance(clientId, secret, projectUid, ai); 162 | HttpResponse response = client.index(); 163 | if (response.isSuccess()) { 164 | LOG.info("Send push message successful!"); 165 | } 166 | LOG.info("code: {}, body: {}", response.getCode(), response.getBody()); 167 | assertTrue("", response.isSuccess()); 168 | ``` 169 | 170 | * 上传媒体文件 返回该文件在服务器的地址 171 | 172 | ```java 173 | InAppMessageClient client = InAppMessageClient.getInstance(clientId, secret, projectUid, ai); 174 | // 构建媒体对象 175 | Media media = Media.newBuilder() 176 | .setName("test.png") 177 | .setFile(fileString) 178 | .build(); 179 | HttpResponse response = client.uploadMedia(media); 180 | if (response.isSuccess()) { 181 | LOG.info("Send push message successful!"); 182 | } 183 | LOG.info("code: {}, body: {}", response.getCode(), response.getBody()); 184 | assertTrue("", response.isSuccess()); 185 | ``` 186 | 187 | -------------------------------------------------------------------------------- /doc/notes/middware(中间件)/limiterRater.md: -------------------------------------------------------------------------------- 1 | QS 接口调用频率限制 2 | 3 | **背景** 4 | 5 | 分析了一下之前 890 的事故,结合之前的代码逻辑聊一下吧. 6 | 7 | 因为我们服务端调用代码的逻辑为异步,所以在请求的过程中是没有阻塞的。 8 | 9 | 10 | 11 | ```scala 12 | def usersList(projectId: Int, ai: String, groupId: String, field: String, attrList: Seq[String], start: Int, end: Int): Future[Seq[UserInfo]] = { 13 | var index = start 14 | val requests = new ArrayBuffer[GroupUsersRequest]() 15 | // todo: 一个登陆用户对应多个设备的情况下 total 小于实际设备数 16 | while (index < end) { 17 | val request = GroupUsersRequest( 18 | ....... 19 | ) 20 | } 21 | // 同时向qs请求 22 | Future.traverse(requests.toList) { request => 23 | requestInsight(request) 24 | }.map(_.flatten) 25 | } 26 | ``` 27 | 28 | 29 | 30 | 18 w 个用户数据 会被切分成为 180 个 1000为单位的查询请求,由于没有阻塞 所以每台机器会瞬间发送 45 个请求到qs,也就是几毫秒发 180 连接到 QS,最终这些请求会变成查询压力打到数据库,将数据打挂。 31 | 32 | 33 | 34 | 目前的解决方案 35 | 36 | 37 | 38 | ```scala 39 | @scala.annotation.tailrec 40 | private def requestInsightBatch(index: Int, contexts: Seq[GroupUserRequestContext], result: Future[Seq[UserInfo]]): Future[Seq[UserInfo]] = { 41 | index match { 42 | case end if end >= contexts.size => result 43 | case i => 44 | val currentResult = for { 45 | userInfos <- result 46 | next <- requestInsight(contexts(i)) 47 | } yield userInfos ++ next 48 | val delayMills = ThreadLocalRandom.current().nextInt(configParams.qsRequestDelayMinMillis, configParams.qsRequestDelayMaxMillis) 49 | TimeUnit.MILLISECONDS.sleep(delayMills) 50 | requestInsightBatch(i + 1, contexts, currentResult) 51 | } 52 | } 53 | ``` 54 | 55 | 采用尾递归的方式,因为要让异步请求一个接一个的请求显然比较麻烦,这里相当于一个flatMap 接着一个 flatMap,然后中间再伴随着 1~5 秒的睡眠。 56 | 57 | 可以判断每次基本的睡眠时间会在 2.5 s 左右,那么4 台机器将会是 0.7 秒一个请求打到 QS 上 一分钟能打 85个请求,也就是能查8w5的用户每分钟。查询的速率还是比较慢,并且没有利用好QS的性能。 58 | 59 | 60 | 61 | 我的解决方案: 62 | 63 | 采用类似guava的 RateLimiter : 64 | 65 | 基于令牌桶算法的限流器 66 | 67 | ```java 68 | public class Test { 69 | 70 | static class Runner implements Runnable{ 71 | 72 | private RateLimiter rateLimiter; 73 | private String name; 74 | public Runner(RateLimiter rateLimiter, String name) { 75 | this.rateLimiter = rateLimiter; 76 | this.name = name; 77 | } 78 | 79 | public void run() { 80 | while (true){ 81 | double acquire = rateLimiter.acquire(); 82 | System.out.println(name+ " current "+ System.currentTimeMillis() + " wait" + acquire); 83 | } 84 | } 85 | } 86 | public static void main(String[] args) { 87 | RateLimiter rateLimiter = RateLimiter.create(0.5); 88 | Runner runner2 = new Runner(rateLimiter,"2"); 89 | Runner runner1 = new Runner(rateLimiter,"1"); 90 | Runner runner4 = new Runner(rateLimiter,"4"); 91 | Runner runner5 = new Runner(rateLimiter,"5"); 92 | Runner runner3 = new Runner(rateLimiter,"3"); 93 | 94 | new Thread(runner1).start(); 95 | new Thread(runner2).start(); 96 | new Thread(runner3).start(); 97 | new Thread(runner5).start(); 98 | new Thread(runner4).start(); 99 | 100 | } 101 | } 102 | 103 | ``` 104 | 105 | 以上示例,创建一个RateLimiter,指定每秒放0.5个令牌(2秒放1个令牌),其输出见下 106 | 1 current 1577935707363 wait0.0 107 | 3 current 1577935709366 wait1.99697 108 | 2 current 1577935711365 wait3.996949 109 | 5 current 1577935713366 wait5.995537 110 | 1 current 1577935715362 wait7.995519 111 | 4 current 1577935717365 wait9.993848 112 | 113 | 但是有个缺点就是没办法在多进程(多机器)内共享这个 RateLimiter 114 | 115 | 我的解决方案是采用 Redis 来存储令牌,同时借鉴了 guava RateLimiter 的内部实现: 116 | 117 | 不是采用传统的每隔两秒放入一次令牌,而是使用一种懒计算的方式,只有在要获取令牌的时候才进行令牌数目计算操作: 118 | 119 | ```scala 120 | case class RedisPermits( 121 | name:String, 122 | maxPermits: Long, 123 | storePermits: Long, 124 | intervalMillis: Long, 125 | nextFreeTicketMillis: Long 126 | ) { 127 | 128 | } 129 | ``` 130 | 131 | 132 | 133 | 这个令牌有几个需要注意的字段 134 | name 令牌的名字 分布式锁的名字也与他有关 135 | maxPermits 最大存储的令牌数 136 | storePermits 存储的令牌数目 137 | intervalMillis 每次放入令牌的间隔 138 | nextFreeTicketMillis 下一次可以获取令牌的时间 139 | 140 | 141 | 142 | 我们的懒计算分为两种可能 143 | 144 | 1. 现在可以获取令牌 145 | 2. 现在不能获取令牌 146 | 147 | 第一种情况就是初始化的时候 `nextFreeTicketMillis` 为 0 ,但是当前的redis 时间已经为 148 | 149 | ![image-20200102115023086](/Users/xiantang/Library/Application Support/typora-user-images/image-20200102115023086.png) 150 | 151 | ```scala 152 | val newPermits = (now - permits.nextFreeTicketMillis) / permits.intervalMillis 153 | val storedPermits = math.min(permits.maxPermits, newPermits + permits.storePermits) 154 | ``` 155 | 156 | 157 | 158 | 因为我们要匀速的请求所以会将最大的存储的数目设置为 1. 也就是当第一次请求的时候就存储了一个令牌。 159 | 160 | 161 | 162 | 第二种情况就是现在还没有到达 `nextFreeTicketMillis` 163 | 164 | ![image-20200102120043445](/Users/xiantang/Library/Application Support/typora-user-images/image-20200102120043445.png) 165 | 166 | ```scala 167 | val tobeSpend = Math.min(permits.storePermits, requiredPermits) 168 | val freshPermits = requiredPermits - tobeSpend 169 | val waitTime = freshPermits * permits.intervalMillis 170 | val storePermits = permits.storePermits - tobeSpend 171 | val nextFreeTicketMillis = permits.nextFreeTicketMillis + waitTime 172 | ``` 173 | 174 | 会将 `nextFreeTicketMillis` 向后推需要睡眠的时间。 175 | 176 | 然后计算出等待的时间,并且睡眠 需要等待的时间; 177 | 178 | ```scala 179 | val lockName = name + ":lock" 180 | lockManager.lock(lockName).flatMap { 181 | case Some(lock) => 182 | for { 183 | _ <- checkPermits(); 184 | waitLength <- reserveAndGetWaitLength(permits); 185 | _ <- lockManager.unLock(lock) 186 | } yield { 187 | waitLength 188 | } 189 | case None => 190 | throw new Exception(s"can not get the lock , name :${lockName}") 191 | } 192 | ``` 193 | 194 | 195 | 196 | ```scala 197 | def acquire(permits: Int): Future[Double] = { 198 | for { 199 | microsToWait <- reserve(permits); 200 | _ <- Future { 201 | TimeUnit.MILLISECONDS.sleep(microsToWait) 202 | } 203 | } yield { 204 | microsToWait 205 | } 206 | 207 | } 208 | ``` 209 | 210 | -------------------------------------------------------------------------------- /doc/notes/goal(目标规划)/7-3到7-4号规划.md: -------------------------------------------------------------------------------- 1 | * - [x] 深入理解JVM 7/3-7/13 2 | - [x] 什么是栈帧? 3 | - [ ] sync 锁降级? 4 | - [ ] JIT 编译器的发展? 逃逸分析? 5 | - [x] string intern 方法? 6 | * - [x] tiny Spring 源码阅读 7/14-7/24 7 | - [x] 为什么要用concurrentHashMap 做 容器 8 | * - [x] Java 并发编程的艺术 7/24-8/01 9 | * - [ ] 公司源码 10 | - [ ] 消息中间件怎么用 用在哪里 11 | - [x] 分布式锁 怎么用 场景 12 | - [x] 分布式锁? setnx()函数 ? 13 | - [x] Redis 连接池 14 | - [x] 负载均衡算法 15 | - [x] 读写分离 主备 数据库 16 | - [x] 限权管理怎么做的 17 | 18 | 10000w行log 查指定时间 19 | 20 | sed -n '/2015-05-04 09:25:55/,/2015-05-04 09:28:55/'p /home/wwwlogs/access.log 21 | 22 | 星期一/星期二/星期四 23 | 24 | 10->12 吃饭 这段时间 看 JVM Spring 25 | 26 | 12->1:30 健身房 锻炼 27 | 28 | 1:45->6:00 写需求 看项目架构 29 | 30 | 6:00->6:30 吃饭 31 | 32 | 6:45->8:00 继续看JVM 并发 Spring 33 | 34 | JVM 7/3 7/13 每天看29页 如果超出就快速进入下一专题 35 | 36 | tiny Spring 7/14 7/24 边看边实现 一天一步 37 | 38 | Java 编程艺术 7/24 8/1 39 | 40 | 41 | 42 | 星期三/星期五 43 | 44 | 10->12 写需求 45 | 46 | 12->1:30 健身房 锻炼 47 | 48 | 1:45->6:00 写需求 看项目架构 49 | 50 | 6:00->6:30 吃饭 51 | 52 | 6:45->8:00 继续看JVM 并发 Spring 53 | 54 | 55 | 56 | 周末 57 | 58 | 9:00 公司 JVM Spring 并发 59 | 60 | 中午吃饭 61 | 62 | 1:30->6:00 写算法 63 | 64 | 6:00 下班 65 | 66 | 晚上看剧放松 打游戏 67 | 68 | 69 | 70 | 71 | 72 | ```java 73 | public CommonRet lockCluster(Integer clusterId,String value) { 74 | CommonRet ret =new CommonRet(); 75 | String key = QLB_L4_REDIS_LOCK_PRE + clusterId; 76 | 77 | try { 78 | 79 | Integer redisTimeOut = qlbDeployService.getQlbRedisLockTimeOut(); 80 | ret.setMsg(value); 81 | //分布式锁 82 | if (LockUtil.tryLock(key,value)) { 83 | LockUtil.expireKey(key, redisTimeOut); 84 | } else { 85 | logger.error("lockRedisJsonValueByKey " + key); 86 | ret.error(clusterEditingMsg); 87 | } 88 | } catch (Exception ex) { 89 | logger.error("cluster lock key:" + key +" " + ex.toString()); 90 | ret.setCode(CommonRet.ERROR); 91 | } 92 | return ret; 93 | } 94 | ``` 95 | 96 | ```java 97 | public class LockUtil { 98 | private static Logger logger = LoggerFactory.getLogger(LockUtil.class); 99 | 100 | /** 101 | * 分布式锁 102 | * @param key 103 | * @param value 104 | * @return 105 | */ 106 | public static boolean tryLock(String key, String value) { 107 | Jedis client = null; 108 | try { 109 | client = RedisWritePool.getClient(); 110 | if (client.setnx(key, value) == 1) { 111 | return true; 112 | } 113 | } catch (Exception ex) { 114 | logger.error("key:" + key + " value:" + value + "." + ex.toString(),ex); 115 | } finally { 116 | RedisWritePool.quitClient(client); 117 | } 118 | return false; 119 | } 120 | 121 | /** 122 | * 分布式锁,添加重试次数 123 | * @param key 124 | * @param value 125 | * @return 126 | */ 127 | public static boolean tryLock(String key, String value,Integer retryTimes) { 128 | for (Integer i=0;i stack1; 37 | private Stack stack2; 38 | private int top = -1; 39 | /** Initialize your data structure here. */ 40 | public MyQueue() { 41 | stack1 = new Stack<>(); 42 | stack2 = new Stack<>(); 43 | } 44 | 45 | /** Push element x to the back of queue. */ 46 | public void push(int x) { 47 | if(stack1.size()==0) top = x; 48 | stack1.push(x); 49 | } 50 | 51 | /** Removes the element from in front of queue and returns that element. */ 52 | public int pop() { 53 | while(stack1.size()!=0){ 54 | stack2.push(stack1.pop()); 55 | } 56 | int res = stack2.pop(); 57 | while(stack2.size()!=0){ 58 | push(stack2.pop()); 59 | } 60 | return res; 61 | } 62 | 63 | /** Get the front element. */ 64 | public int peek() { 65 | return top; 66 | } 67 | 68 | /** Returns whether the queue is empty. */ 69 | public boolean empty() { 70 | return stack1.isEmpty(); 71 | } 72 | } 73 | 74 | /** 75 | * Your MyQueue object will be instantiated and called as such: 76 | * MyQueue obj = new MyQueue(); 77 | * obj.push(x); 78 | * int param_2 = obj.pop(); 79 | * int param_3 = obj.peek(); 80 | * boolean param_4 = obj.empty(); 81 | */ 82 | ``` 83 | 84 | ## 215. Kth Largest Element in an Array 85 | 86 | 87 | Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element. 88 | 89 | 90 | Example 1: 91 | ``` 92 | Input: [3,2,1,5,6,4] and k = 2 93 | Output: 5 94 | ``` 95 | 96 | Example 2: 97 | ``` 98 | Input: [3,2,3,1,2,4,5,5,6] and k = 4 99 | Output: 4 100 | ``` 101 | 102 | 我采用的是分治的方法解决这个问题也可以采用MInheap来完成 103 | 就是选择第一个字符作为基准,将比这个大的数字放在他前面,比他小的放在他后面 然后交换到数组中央。 104 | 这样他所在的坐标对应的值就是他的第 坐标+1 大的数 105 | 如果k 比 当前索引大 就继续寻找左边,比当前索引小 就继续寻找右边。 106 | 107 | ```java 108 | class Solution { 109 | public int findKthLargest(int[] nums, int k) { 110 | if(nums==null || nums.length == 0) return 0; 111 | int left = 0; 112 | int right = nums.length-1; 113 | while(true){ 114 | int pos = partition(nums,left,right); 115 | if(pos+1 == k){ 116 | return nums[pos]; 117 | } 118 | else if(pos +1>k){ 119 | right = pos-1; 120 | }else 121 | left = pos+1; 122 | } 123 | } 124 | 125 | private int partition(int[] nums,int left,int right){ 126 | int pivot = nums[left]; 127 | int l = left+1; 128 | int r = right; 129 | while(l<=r){ 130 | if(nums[l]pivot){ 131 | swap(nums,l++,r--); 132 | } 133 | if(nums[l]>=pivot) l++; 134 | if(nums[r]<=pivot) r--; 135 | } 136 | swap(nums,left,r); 137 | return r; 138 | } 139 | private void swap(int[] nums,int i,int j){ 140 | int temp = nums[i]; 141 | nums[i] = nums[j]; 142 | nums[j] = temp; 143 | } 144 | } 145 | ``` 146 | 147 | ## 295. Find Median from Data Stream 148 | 149 | 150 | Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. 151 | 152 | So the median is the mean of the two middle value. 153 | 154 | 155 | For example: 156 | 157 | ``` 158 | [2,3,4], the median is 3 159 | [2,3], the median is (2 + 3) / 2 = 2.5 160 | ``` 161 | 162 | 163 | Design a data structure that supports the following two operations: 164 | * void addNum(int num) - Add a integer number from the data stream to the data structure. 165 | * double findMedian() - Return the median of all elements so far. 166 | 167 | Example: 168 | 169 | ``` 170 | addNum(1) 171 | addNum(2) 172 | findMedian() -> 1.5 173 | addNum(3) 174 | findMedian() -> 2 175 | ``` 176 | 177 | 这道中位数的题目我是采用最小堆和最大堆做的 178 | 179 | 一个最大堆保存一半较小的数据 180 | 另一个最小堆保存一半较大的数据 181 | 182 | 然后采取平衡手段保证两个堆的大小差小于2 183 | 184 | ![](http://ww1.sinaimg.cn/large/006d4JA0ly1g1t4z7hwkqj30h70dpjsr.jpg) 185 | 186 | ```java 187 | 188 | class MedianFinder { 189 | private PriorityQueue l; 190 | private PriorityQueue r; 191 | /** initialize your data structure here. */ 192 | public MedianFinder() { 193 | r = new PriorityQueue(); 194 | l = new PriorityQueue(new Comparator(){ //大顶堆,容量11 195 | @Override 196 | public int compare(Integer i1,Integer i2){ 197 | return i2-i1; 198 | } 199 | }); 200 | } 201 | 202 | public void addNum(int num) { 203 | if(l.size() == 0 || num<=l.peek()){ 204 | l.add(num); 205 | } 206 | else { 207 | r.add(num); 208 | } 209 | if(l.size()r.size()){ 221 | return l.peek(); 222 | } 223 | else{ 224 | double res = ((double)l.peek()+(double)r.peek())/2; 225 | return res; 226 | } 227 | } 228 | } 229 | 230 | /** 231 | * Your MedianFinder object will be instantiated and called as such: 232 | * MedianFinder obj = new MedianFinder(); 233 | * obj.addNum(num); 234 | * double param_2 = obj.findMedian(); 235 | */ 236 | 237 | 238 | ``` -------------------------------------------------------------------------------- /doc/notes/java/JavaConcurrent.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | * 多线程的通信,同步方式 3 | * volatile和synchronized的区别 4 | * 乐观锁与悲观锁? 5 | * 乐观锁它是怎么实现的? 6 | * 悲观锁呢? 7 | 8 | # Java并发 9 | 10 | ## 乐观锁 CAS 11 | 12 | compare and swap(比较与交换),是一种有名的无锁算法。不用锁的情况下实现多线程的变量同步,在没有线程阻塞 13 | 的情况下实现变量同步,也叫非阻塞同步。当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。适用于读较多的情况。 14 | 三个操作数: 15 | 16 | * 需要读写的内存值 V 17 | * 进行比较的值(预期值) A 18 | * 拟写入的新值 B 19 | 当且仅当预期值和内存值相等,将内存V修改为B,否则什么都不做。一般来说是一个自旋的操作,不断的重试。 20 | * CAS, CPU指令,在大多数处理器架构,包括IA32、Space中采用的都是CAS指令,CAS的语义是“我认为V的值应该为A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际为多少”, 21 | 22 | 23 | 24 | ## 悲观锁 25 | * 资源共享只给一个线程,其他线程阻塞,用完在给其他线程。 26 | * 适用于写较多的情况。 27 | 28 | 29 | ## synchronized 使用场景 30 | 31 | 线程具有五大状态: 32 | * 新建状态:新建线程对象,并没有调用start()方法之前。 33 | * 就绪状态:调用start()方法之后线程就进入就绪状态,但是并不是说只要调用start()方法线程就马上变为当前线程。 34 | * 运行状态:线程被设置为当前线程,开始执行run()方法。就是线程进入运行状态 35 | * 阻塞状态:线程被暂停,比如说调用sleep()方法后线程就进入阻塞状态 36 | * 死亡状态:线程执行结束 37 | 38 | ![](http://www.blogjava.net/images/blogjava_net/santicom/360%E6%88%AA%E5%9B%BE20110901211600850.jpg) 39 | 40 | 锁类型: 41 | * 可重入锁(synchronized和ReentrantLock):在执行对象中所有同步方法不用再次获得锁 42 | * 可中断锁(synchronized就不是可中断锁,而Lock是可中断锁):在等待获取锁过程中可中断 43 | * 公平锁(ReentrantLock和ReentrantReadWriteLock): 按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利 44 | * 读写锁(ReadWriteLock和ReentrantReadWriteLock):对资源读取和写入的时候拆分为2部分处理,读的时候可以多线程一起读,写的时候必须同步地写 45 | 46 | 47 | ## Synchronized与Lock的区别 48 | 49 | * synchronized关键字 Lock是接口 50 | * Synchronized获取锁的线程执行完同步代码,释放锁,线程执行发生异常,jvm会让线程释放锁。Lock 在finally中必须释放锁,不然容易造成死锁。 51 | * Synchronized无法判断锁状态,Lock可以判断。 52 | * synchronized 少量同步,Lock可以提高线程进行读操作的效率(读写分离) 53 | 54 | | 类型 | synchronized | Lock | 55 | |---| ----- | -------- | 56 | |存在层次| Java的关键字,在jvm层次 | 一个类 | 57 | |锁的释放| 获取锁执行完成同步代码,执行发生异常,会有一个monitorexit 来退出 | 必须在finally释放锁 | 58 | |锁的获取|假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待|分情况而定,Lock有多个锁获取的方式,具体下面会说道,大致就是可以尝试获得锁,线程可以不用一直等待| 59 | | 锁状态 | 无法判断 |可以判断 | 60 | | 锁类型 | 可重入 不可中断 非公平 | 可重入 可判断 可公平(两者皆可) | 61 | 62 | 63 | ## synchronized 的锁优化 64 | 65 | 锁的升级策略: 66 | 偏向锁->轻量级锁->重量级锁 67 | ![](https://images2015.cnblogs.com/blog/820406/201604/820406-20160424163618101-624122079.png) 68 | 偏向锁、轻量锁的状态转换以及对象MarkWord的关系 69 | ### 偏向锁 70 | 71 | 无竞争的情况下的同步原语,在无竞争的情况下吧整个同步操作消除。如果一个线程获得了锁,那么锁就会进入偏向模式Mark Word结构就会变成偏向锁结构,当线程再次请求的时候,就不需要任何同步操作。 72 | 73 | ### 轻量级锁 74 | 轻量级锁能够提升程序性能的依据是“对绝大部分的锁,在整个同步周期内都不存在竞争”,轻量级锁所适应的场景是线程交替执行同步块的场合。 75 | 76 | 77 | 对象实例由对象头,实例数组组成,其中对象头包括markword和类型指针,如果是数组,还包括数组的长度。 78 | 79 | HotSpot 虚拟机的对象头 80 | | 类型 | 32位JVM | 64位JVM | 81 | |---| ----- | -------- | 82 | |markword| 32bit | 64bit | 83 | |类型指针| 32bit | 64bit,开启指针压缩时为32bit | 84 | |数组长度(可选)| 32bit |32bit | 85 | 86 | 对象头的markword: 87 | ![](https://img-blog.csdnimg.cn/20190115142040348.png) 88 | 89 | 轻量锁操作之前的堆栈与对象的状态: 90 | ![](https://images2015.cnblogs.com/blog/820406/201604/820406-20160424105442866-2111954866.png) 91 | 92 | 当代码进入同步块的时候,如果同步没有被锁定(标志位为01)首先迅即会将当前栈帧中建立一个名为锁记录的空间LockRecord,拷贝指定对象的markword。 93 | ![](https://images2015.cnblogs.com/blog/820406/201604/820406-20160424105540163-1019388398.png) 94 | 虚拟机将使用CAS操作尝试将对象的markword 更新指向 95 | 当前线程的栈。如果更新失败就说明这个对象已经被其他线程占用。 96 | 如果有两个线程同时抢夺一个锁,就会将锁的标识变为"10",MarkWord 中存储的就是重量锁(互斥量)的指针,后面等待的线程也要进入阻塞状态。 97 | 98 | ### 锁的消除 99 | 100 | ```java 101 | public String concatString(String s1, String s2, String s3) { 102 | return s1 + s2 + s3; 103 | 104 | } 105 | ``` 106 | 在JDK1.5 之后的版本会被优化成为StringBuilder的连续append() 107 | 108 | 因为对象不会被发布都这个方法之外的区域 109 | 110 | ```java 111 | public java.lang.String concatString(java.lang.String, java.lang.String, java.lang.String); 112 | Code: 113 | 0: new #2 // class java/lang/StringBuilder 114 | 3: dup 115 | 4: invokespecial #3 // Method java/lang/StringBuilder."":()V 116 | 7: aload_1 117 | 8: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 118 | 11: aload_2 119 | 12: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 120 | 15: aload_3 121 | 16: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 122 | 19: invokevirtual #5 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 123 | ``` 124 | 也就是所谓的栈封闭,编译器观察sb对象发现这个作用域在方法内部,就是说sb对象的引用是不会`逃逸`到concatString()方法外部。 125 | 126 | ## 什么是线程不安全 127 | 线程安全:当多线程访问某个类的时候,这个类始终能表现出正确的行为,就叫做线程安全。 128 | 非线程安全是指多线程操作同一个对象可能会出现问题。 129 | 130 | ## 对象的共享 131 | volatile 变量不会被缓存存在寄存器或者其他处理器不可见的地方,在读取volatile变量的时候总会返回最新写入的值。 132 | 注意:volatile 语义不能保证递增操作的原子性。 133 | 134 | 发布对象(publish): 135 | * 对象引用保存到一个公有的静态变量中。 136 | * 用非私有方法返回一个引用。 137 | * 当把一个对象传入给一个外部方法的时候,相当于发布这个对象。 138 | * 发布一个内部类的实例。 139 | 140 | ### final域 141 | 142 | final域可以确保初始化过程的安全性 143 | 144 | 145 | 146 | ## 线程池 147 | 148 | ### 管理队列任务 149 | 150 | ThreadPoolExecutor 允许提供一个BlockingQueue 来保存等待执行的任务 151 | 152 | 主要有3中不同的队列 153 | 154 | * 有界队列 155 | 有助于避免资源耗尽的情况发生: 156 | * ArrayBlockingQueue 157 | * LinkedBlockingQueue 158 | * PriorityBlockingQueue 159 | 但是队列填满怎么办? 160 | 使用**饱和策略** 161 | 162 | * 无界队列 163 | * 同步移交(Synchronous Handoff)队列 164 | 对于非常大的或者无界的线程池,使用SynchronousQueue来避免任务排队,SynchronousQueue不是一个真正的队列,而是一种线程之间的移交机制。 165 | 166 | ## 条件谓词 167 | 168 | * 通常都有一个条件谓词 169 | * 在调用wait之前先测试条件谓词 170 | * 调用wait的之前测试条件谓词,并且wait中返回时再次进行测试 171 | * 调用wait notify notifyall 等方法的时候,一定要持有与条件队列相关的锁 172 | 173 | 174 | 175 | ### volatile 176 | 177 | Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。如果一个字段被声明成volatile,Java线程内存模型确保所有线程看到这个变量的值是一致的. 178 | 179 | 内存屏障:memory barriers 是一组处理器指令,实现对内存操作的顺序限制。 180 | 181 | - 将当前处理器缓存行的数据写回系统内存 182 | - 这个写回内存的操作会使其他CPU里缓存了该内存的数据无效 183 | 184 | 就是一个cpu向内存写入数据的时候,会让其他处理器通过嗅探的方式检查自己的数据是否过期了,如果过期就使他无效,如果存在修改这条缓存行的数据的时候,就重新从系统内存中把数据读到处理器缓存中。 185 | 186 | 实现原则: 187 | 188 | - Lock前缀指令会引起处理器缓存回写到内存. 189 | - 一个处理器的缓存回写到内存会导致其他处理器的缓存无效. 190 | 191 | happens-before 原则 192 | 193 | 在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在happens-before关 194 | 系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间。 195 | 196 | 如果A线程的写操作a与B线程的读操作b之间存在happens-before关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见 197 | 198 | 程序员对于这两个操作是否真的被重排序并不关心,程序员关心的是程序执行时的语义不能被改变 199 | 200 | ![1562855661632](../../images/1562855661632.png) 201 | 202 | as-if-serial语义把单线程程序保护了起来,遵守as-if-serial语义的编译器、runtime和处理器 203 | 共同为编写单线程程序的程序员创建了一个幻觉:单线程程序是按程序的顺序来执行的。as- 204 | if-serial语义使单线程程序员无需担心重排序会干扰他们,也无需担心内存可见性问题。 -------------------------------------------------------------------------------- /doc/notes/algorithm(算法)/链表.md: -------------------------------------------------------------------------------- 1 | ## 92. Reverse Linked List II 2 | 3 | 4 | Reverse a linked list from position m to n. Do it in one-pass. 5 | 6 | 7 | ``` 8 | Input: 1->2->3->4->5->NULL, m = 2, n = 4 9 | Output: 1->4->3->2->5->NULL 10 | ``` 11 | 12 | ![](http://ww1.sinaimg.cn/large/006d4JA0ly1g1kvt1doqij30o607i74a.jpg) 13 | 14 | ![](http://ww1.sinaimg.cn/large/006d4JA0ly1g1kvyokmawj30q208hjre.jpg) 15 | 16 | 代码: 17 | 18 | ```java 19 | 20 | class Solution { 21 | public ListNode reverseBetween(ListNode head, int m, int n) { 22 | if(head == null) { 23 | return null; 24 | } 25 | ListNode dummy = new ListNode(0); 26 | dummy.next = head; 27 | ListNode pre = dummy; 28 | for(int i = 0 ; i2->3->4->5->NULL 54 | Output: 5->4->3->2->1->NULL 55 | ``` 56 | 57 | ![](http://ww1.sinaimg.cn/large/006d4JA0ly1g1kwldrba4j30pf0f20su.jpg) 58 | 59 | ```java 60 | class Solution { 61 | public ListNode reverseList(ListNode head) { 62 | 63 | ListNode pre = null; 64 | ListNode curr = head; 65 | while(curr != null){ 66 | ListNode next_temp = curr.next; 67 | curr.next = pre; 68 | pre = curr; 69 | curr = next_temp; 70 | } 71 | return pre; 72 | } 73 | } 74 | ``` 75 | 76 | ## 24. Swap Nodes in Pairs 77 | 78 | 79 | Given a linked list, swap every two adjacent nodes and return its head. 80 | You may not modify the values in the list's nodes, only nodes itself may be changed. 81 | 82 | ``` 83 | Given 1->2->3->4, you should return the list as 2->1->4->3. 84 | ``` 85 | 86 | 为什么要使用dummy: 87 | 88 | * head 位置会跳到第二个位置 89 | 90 | ```java 91 | class Solution { 92 | public ListNode swapPairs(ListNode head) { 93 | if(head == null || head.next == null){ 94 | return head; 95 | } 96 | ListNode dummy = new ListNode(0); 97 | dummy.next = head; 98 | ListNode cur = dummy; 99 | while(cur.next!=null && cur.next.next!=null){ 100 | ListNode first = cur.next; 101 | ListNode second = cur.next.next; 102 | first.next = second.next; 103 | second.next =first; 104 | cur.next = second; 105 | cur = first; 106 | } 107 | return dummy.next; 108 | } 109 | } 110 | ``` 111 | 112 | ## 142. Linked List Cycle II 113 | 114 | 115 | 116 | Given a linked list, return the node where the cycle begins. If there is no cycle, return `null`. To represent a cycle in the given linked list, we use an integer `pos` which represents the position (0-indexed) in the linked list where tail connects to. If `pos` is `-1`, then there is no cycle in the linked list. 117 | 118 | ![](http://ww1.sinaimg.cn/large/006d4JA0ly1g1lwwsqr47j30j20judgd.jpg) 119 | 120 | * 定义快慢指针判断是否是环 121 | * 如果是环,就将 slow 指针移到开头,保持 fast 指针的位置 122 | * 两个指针每次只走一步,这一次的交点就是环的入口 123 | 124 | 道理我都懂但是为什么呢?? 为什么要放到开头呢?? 下面我给出我的数学证明! 125 | 126 | 127 | 首先定义 128 | 129 | ![](http://ww1.sinaimg.cn/large/006d4JA0ly1g1lxl3w0zhj30cb09j0t5.jpg) 130 | 131 | * 链表入环口为 d 132 | * 链表头的位置是 h 133 | * 快慢指针初次相遇的位置为 c 134 | * 链表的总长度为 L 135 | * 链表头到入环口的长度为 A 136 | * 入环口到快慢指针初次相遇的位置的长度是 X 137 | * 环的长度是 R 138 | 139 | 首先可以确定在相遇的时候快指针可能在里面转了n圈 140 | 并且慢指针并没有走完一圈 141 | 并且快慢指针具有一个性质,快指针永远是慢指针速度的两倍 142 | 我们设定头节点 h 到快慢指针初次相遇的位置 c 的位置的长度为 S 143 | 144 | 我们可以推断出一下等式: 145 | 146 | ``` 147 | n*R + S = 2*S 148 | // 等式前面是快指针走的长度,后面是两倍的慢指针走的长度 149 | n*R = S 150 | ``` 151 | 152 | 又因为 S 的长度是 A 和 X 的和 153 | 154 | ``` 155 | S = X+A 156 | ``` 157 | 158 | 结合两个等式可以推断出 159 | 160 | ``` 161 | A + X = n*R 162 | A + X = (n-1)R + (L-A) 163 | A = (n-1)R + (L-A-X) // L-A 就是环的长度R 164 | ``` 165 | 166 | 那么 R-X 的长度就是 c到d 的长度 167 | 168 | 令 slow 从头节点 点出发,fast 从c 出发,每次移动 1 就可以到达入环口 d。 169 | 170 | 171 | ```java 172 | 173 | public class Solution { 174 | public ListNode detectCycle(ListNode head) { 175 | 176 | ListNode fast = head; 177 | ListNode slow = head; 178 | boolean isCycle = false; 179 | while(fast!=null && fast.next!=null){ 180 | fast = fast.next.next; 181 | slow = slow.next; 182 | if(fast == slow){ 183 | isCycle = true; 184 | } 185 | } 186 | if(isCycle){ 187 | slow = head; 188 | while(true){ 189 | slow = slow.next; 190 | fast = fast.next; 191 | if(slow == fast){ 192 | return slow; 193 | } 194 | } 195 | } 196 | else return null; 197 | } 198 | } 199 | 200 | 201 | ``` 202 | 203 | ## 138. Copy List with Random Pointer 204 | 205 | 206 | 207 | A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. 208 | Return a `deep copy` of the list. 209 | 210 | ![](https://discuss.leetcode.com/uploads/files/1470150906153-2yxeznm.png) 211 | 212 | ``` 213 | 214 | Input: 215 | {"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1} 216 | 217 | Explanation: 218 | Node 1's value is 1, both of its next and random pointer points to Node 2. 219 | Node 2's value is 2, its next pointer points to null and its random pointer points to itself. 220 | ``` 221 | 222 | 这道题的难点主要在于如何处理随机指针的问题 223 | 我们可以通过第一遍遍历生成新节点的同时建立一个原节点和拷贝节点的哈希 224 | 表,第二遍遍历给随机指针赋值的时候,查找时间是常数级别的。 225 | 226 | ```java 227 | class Solution { 228 | Map nodeCache = new HashMap(); 229 | public Node copyRandomList(Node head) { 230 | if(head == null){ 231 | return null; 232 | } 233 | Node copyNode = new Node(head.val,head.next,head.random); 234 | nodeCache.put(head,copyNode); 235 | if(head.next!=null){ 236 | copyRandomList(head.next); 237 | copyNode.next = nodeCache.get(copyNode.next); 238 | copyNode.random = nodeCache.get(copyNode.random); 239 | }else{ 240 | copyNode.random = nodeCache.get(copyNode.random); 241 | } 242 | return copyNode; 243 | } 244 | } 245 | ``` -------------------------------------------------------------------------------- /doc/notes/tomcat/Tomcat 源码解析 (3) - 容器.md: -------------------------------------------------------------------------------- 1 | # 容器 2 | 3 | servlet 容器是用来处理servlet 资源,为Web 客户端填充 response 的模块 4 | 5 | Tomcat 有4种容器: 6 | 7 | * Engine 整个 Catalina servelt 引擎 8 | * Host 包含了一个或者多个Context 容器的虚拟主机 9 | * Context 表示一个web app 一个context 有多个Wrapper 10 | * Wrapper 表示一个独立的servelt 11 | 12 | 这些容器都实现了Container 接口 13 | 14 | 我们的本章的上半部分主要讲解的是Wrapper 与 Context 15 | 16 | ## Container 17 | 18 | 因为所有的容器都实现于Tomcat 的Container 接口所以我们讲解一下Container 接口 19 | 20 | ![img](../doc/images/738818-20181211000636874-1536263943.png) 21 | 22 | Container 主要需要实现的方法是 addChild() 和 removeChild() 23 | 24 | ```java 25 | /** 26 | * Add a new child Container to those associated with this Container, 27 | * if supported. Prior to adding this Container to the set of children, 28 | * the child's setParent() method must be called, with this 29 | * Container as an argument. This method may thrown an 30 | * IllegalArgumentException if this Container chooses not 31 | * to be attached to the specified Container, in which case it is not added 32 | * 33 | * @param child New child Container to be added 34 | * 35 | * @exception IllegalArgumentException if this exception is thrown by 36 | * the setParent() method of the child Container 37 | * @exception IllegalArgumentException if the new child does not have 38 | * a name unique from that of existing children of this Container 39 | * @exception IllegalStateException if this Container does not support 40 | * child Containers 41 | */ 42 | public void addChild(Container child); 43 | /** 44 | * Remove an existing child Container from association with this parent 45 | * Container. 46 | * 47 | * @param child Existing child Container to be removed 48 | */ 49 | public void removeChild(Container child); 50 | ``` 51 | 52 | 并且更具上面的注释,在实现add 方法的时候必须对传入的子容器设置父容器。 53 | 54 | 55 | 56 | ## Host 和 Engine 是什么? 57 | 58 | 如果你需要在Tomcat 上部署多个Context 容器的话,你需要使用Host 容器,如果只有一个Context 容器的话,理论上不需要Host 容器,但是在Tomcat 的实际部署的时候,总是会使用一个Host 容器。所以他基本只是作为一个包含Context 容器的父容器。 59 | 60 | 61 | 62 | 而Engine 容器则是处于最顶层的容器,默认情况下Tomcat 会使用Engine 容器并且Engine 容器中包含一个 Host 容器。 63 | 64 | ## 管道 65 | 66 | Tomcat 并没有采用遍历Valve 的方式去实现阀的遍历执行。也没有采用Tomcat4 之前的实现采用ValveContext的实现。 67 | 68 | 但是我们可以稍微了解下这个Valve Context 的实现。 69 | 70 | 类似于Java 的双亲委派机制。 71 | 72 | ![](../doc/images/images.png) 73 | 74 | 对于每个阀调用的时候都会传入一个叫做ValveContext的实例。这个ValveContext 实例可以获取到这个管道中所有的阀,所以可以使用他的invokeNext 来调用之后的阀。 75 | 76 | ```java 77 | public void invoke(Request req,Response res,ValveContext context){ 78 | context.invokeNext(req,res); 79 | // 下面才是当前阀的逻辑 80 | } 81 | ``` 82 | 83 | 我觉得这里使用递归调用下面的阀的过程的好处是: 84 | 85 | 如果可以通过回搠可以对之前执行完成的阀进行一些额外的操作,如果你需要将当前的状态传递到下一个阀中去的话,就可以将invoke() 放置在方法末尾,如果你需要基于之前的阀进行操作的话,你可以将invoke()放置在方法开头,这样大大能提高用户DIY 代码的灵活性。 86 | 87 | ![img](../doc/images/345531-20160330111438473-1015724073.png) 88 | 89 | 可以很清晰的看到,对于阀和阀之间都是采用双向箭头来表示,因为可以通过回搠回到上一个阀中。 90 | 91 | 在Tomcat 7的实现中则是将Valve 设置成为单项链表的实现,每个pipeline的基础阀在链表的尾部,并且如果有新的valve 被嵌入的时候,将他插入在尾部,并且在基础阀的前一个节点,这也是用普通的遍历所达不到的效果。 92 | 93 | ```java 94 | // Add this Valve to the set associated with this Pipeline 95 | if (first == null) { 96 | first = valve; 97 | valve.setNext(basic); 98 | } else { 99 | Valve current = first; 100 | while (current != null) { 101 | if (current.getNext() == basic) { 102 | current.setNext(valve); 103 | valve.setNext(basic); 104 | break; 105 | } 106 | current = current.getNext(); 107 | } 108 | } 109 | ``` 110 | 111 | 所以如果我们要调用Pipeline的话就会从链表头部开始调用直到调用到链表的末尾,去调用子容器的Pipeline 不断委托下去,这样有个好处就是可以将原本杂乱无章的代码逻辑,采用流水线的方式执行,并且能够让每个Valve 都有接触资源的机会,也方便于之后的代码维护,可以对阀进行有序的增删改。 112 | 113 | Tomcat 所有容器的Valve 调用如下图所示: 114 | 115 | 116 | 117 | ![img](../doc/images/81282f8c4d26fcf5375392a2a856a4bc.png) 118 | 119 | ```java 120 | public class CoyoteAdapter implements Adapter { 121 | /** 122 | * 适配器调用Engine的第一个阀 123 | */ 124 | @Override 125 | public void service(org.apache.coyote.Request req, 126 | org.apache.coyote.Response res) 127 | throws Exception { 128 | connector.getService().getContainer() 129 | .getPipeline().getFirst(). 130 | invoke(request, response); // 一个复杂的调用 131 | } 132 | } 133 | ``` 134 | 135 | ```java 136 | final class StandardEngineValve 137 | extends ValveBase { 138 | /** 139 | * Engine 调用 140 | */ 141 | @Override 142 | public final void invoke(Request request, Response response) 143 | throws IOException, ServletException { 144 | 145 | // Select the Host to be used for this Request 146 | Host host = request.getHost(); 147 | if (host == null) { 148 | response.sendError 149 | (HttpServletResponse.SC_BAD_REQUEST, 150 | sm.getString("standardEngine.noHost", 151 | request.getServerName())); 152 | return; 153 | } 154 | if (request.isAsyncSupported()) { 155 | request.setAsyncSupported(host.getPipeline().isAsyncSupported()); 156 | } 157 | 158 | // Ask this Host to process this request 159 | host.getPipeline().getFirst().invoke(request, response); 160 | } 161 | 162 | } 163 | ``` 164 | 165 | ```java 166 | /** 167 | *Context 调用 Wrapper 的第一个阀 168 | */ 169 | @Override 170 | public final void invoke(Request request, Response response) 171 | throws IOException, ServletException { 172 | 173 | // Disallow any direct access to resources under WEB-INF or META-INF 174 | MessageBytes requestPathMB = request.getRequestPathMB(); 175 | if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0)) 176 | || (requestPathMB.equalsIgnoreCase("/META-INF")) 177 | || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0)) 178 | || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) { 179 | response.sendError(HttpServletResponse.SC_NOT_FOUND); 180 | return; 181 | } 182 | 183 | // Select the Wrapper to be used for this Request 184 | Wrapper wrapper = request.getWrapper(); 185 | if (wrapper == null || wrapper.isUnavailable()) { 186 | response.sendError(HttpServletResponse.SC_NOT_FOUND); 187 | return; 188 | } 189 | 190 | // Acknowledge the request 191 | try { 192 | response.sendAcknowledgement(); 193 | } catch (IOException ioe) { 194 | container.getLogger().error(sm.getString( 195 | "standardContextValve.acknowledgeException"), ioe); 196 | request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe); 197 | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 198 | return; 199 | } 200 | 201 | if (request.isAsyncSupported()) { 202 | request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported()); 203 | } 204 | wrapper.getPipeline().getFirst().invoke(request, response); 205 | } 206 | 207 | ``` 208 | 209 | -------------------------------------------------------------------------------- /doc/notes/network(计算机网络)/网络概论笔记.md: -------------------------------------------------------------------------------- 1 | ## 网络概论笔记 2 | 3 | 4 | 5 | ![1564670779560](../../images/1564670779560.png) 6 | 7 | ## 传输**层** 8 | 9 | TCP:客户端与服务器端需要维持会话,TCP需要传输的文件进行分段 传输进行可靠传输 10 | 11 | 流量控制功能 12 | 13 | UDP: 一个数据包就能够完成数据传输,不需要建立绘画,不需要流量控制 14 | 15 | etc:DNS 16 | 17 | 屏幕 广播 (多播) 18 | 19 | 20 | 21 | 传输层协议和应用层协议的关系 22 | 23 | ![1565518391960](../../images/1565518391960.png) 24 | 25 | HTTP =TCP + 80 26 | 27 | HTTPS = TCP+443 28 | 29 | RDP = TCP+3389 30 | 31 | FTP = TCP + 31 32 | 33 | telnet = TCP + 23 34 | 35 | SQL = TCP+1433 36 | 37 | DNS = UDP + 53 38 | 39 | POP3 = TCP +110 40 | 41 | IP 层协议主要提供了主机之间的逻辑通讯 42 | 43 | TCP/UDP 主要提供了应用程序之间的逻辑通讯 44 | 45 | 传输层的端口:TCP 6 UDP 17 ICMP 17 46 | 47 | 登记端口号:数值1024~49151 48 | 49 | 客户端端口号:数值49152~6553 50 | 51 | 52 | 53 | ### UDP 54 | 55 | ![1565613365296](../../images/1565613365296.png) 56 | 57 | 58 | 59 | ![1565613534148](../../images/1565613534148.png) 60 | 61 | 需要从 网络层提炼出20个字节 一起计算首部 62 | 63 | #### 伪首部 64 | 65 | 源地址 66 | 67 | ![1565613764987](../../images/1565613764987.png) 68 | 69 | 目标地址 70 | 71 | ![1565613821427](../../images/1565613821427.png) 72 | 73 | 源地址+目标地址 总和为8个字节 74 | 75 | ![1565613896473](../../images/1565613896473.png) 76 | 77 | 全 0 和 UDP 协议号以及 UDP 的长度 78 | 79 | 就组成了一个伪首部 80 | 81 | ![1565614271546](../../images/1565614271546.png) 82 | 83 | 84 | 85 | 86 | 87 | ### TCP 88 | 89 | TCP 学什么? 90 | 91 | * TCP 特点 92 | * 如何实现可靠传输 93 | * 如何实现流量控制 94 | * 如何避免网络拥塞 95 | 96 | 面向连接的传输协议 97 | 98 | 每条 TCP 连接只能有两个端点 点对点 99 | 100 | 提供可靠传输的服务 101 | 102 | TCP 提供全双工通讯: 因为需要反馈 才能确定自己发的消息是否是对方能听到的 103 | 104 | 面向字节流 105 | 106 | 107 | 108 | socket = (IP地址:端口) 109 | 110 | 111 | 112 | 113 | 114 | ![1559226409029](../../images/1559226409029.png) 115 | 116 | SEQ:你data中第一个byte的seq number 117 | 118 | ACKs: 你希望下一次收到的seq number (隐含了之前都收到了) 119 | 120 | 对于没有按照顺序的封包:看开发者的实现方式。 121 | 122 | 123 | 124 | #### TCP Round Trip Time and Timeout 125 | 126 | timeout 应该大于RTT 127 | 128 | 使用 SampleRTT:采用取样的方式,测量时间直到收到ACK,忽略重送的封包时间。 129 | 130 | 131 | 132 | ![1559226186513](../../images/1559226186513.png) 133 | 134 | 135 | 136 | #### 快速重传 137 | 138 | resend segment before timer expires 139 | 140 | 在定时器结束之前重传。 141 | 142 | 143 | 144 | 145 | 146 | ### 1. 如何实现可靠传输与三次握手 147 | 148 | #### 停止等待协议 149 | 150 | ##### 无差错 151 | 152 | ![1565616025008](../../images/1565616025008.png) 153 | 154 | ##### 有差错 155 | 156 | ![1565616052121](../../images/1565616052121.png) 157 | 158 | 超时重传的等待时间为一个往返的时间稍微长一些 159 | 160 | ##### 确认丢失 161 | 162 | ![1565616247238](../../images/1565616247238.png) 163 | 164 | ##### 确认迟到 165 | 166 | ![1565616348312](../../images/1565616348312.png) 167 | 168 | 169 | 170 | 使用上述的确认和重传机制,就可以在不可靠的网络上实现可靠的通讯。 `自动重传请求 ARQ` 171 | 172 | #### 信道利用率 173 | 174 | RTT 数据包往返时间 175 | $$ 176 | U = \frac{T_D}{T_D+RTT+T_A} 177 | $$ 178 | 发送一个数据包的时间占用总共是时间的比率 179 | 180 | 所以需要提高 Td 的占比就可以提高信道利用率 181 | 182 | 流水线传输:发送方连续的发送多个分组 183 | 184 | ![1565617807857](../../images/1565617807857.png) 185 | 186 | 187 | 188 | 但是问题又来了 如何实现可靠的传输在流水线传输的基础上: 189 | 190 | 我们使用一个窗口将数据包放在里面 191 | 192 | ![](../../images/1565618081029.png) 193 | 194 | 每当最左边的数据包收到就向左移动一格 195 | 196 | #### 累计确认 197 | 198 | 对于发送方A 和 接受方B 199 | 200 | ![1565618412458](../../images/1565618412458.png) 201 | 202 | B 收到了 3个数据包分别是 1 2 3 这时 B 对应 3 的ACK 发送到了A 但是 1 2 的ACK 没有收到,这个时候 A 就会默认 1 和 2 是已经收到了,不需要确认了。 203 | 204 | #### 返回最大有序的ACK 205 | 206 | [![1559222070250](../../images/1559222070250-1565618604591.png)](https://github.com/xiantang/Java-BackEnd-Notes/blob/master/doc/images/1559222070250.png) 207 | 208 | 如果是out-of-order: 209 | 210 | - 丢弃封包 211 | - 回复一个最大的有序的数组 212 | 213 | 就像上图如果中间一个2号封包丢失了,receiver收到3号封包的时候,是处于out-of-order的情况所以需要返回一个最大的in-order数字也就是回复1号。 214 | 215 | 216 | 217 | TCP 每发送一个报文段,就要对报文段设置一次计时器。只要计时器设置的重传时间还没有收到确认,就要重传这一段报文段。 218 | 219 | 220 | 221 | ##### TCP 报文段 segment 222 | 223 | TCP 首部 224 | 225 | ![1565619272559](../../images/1565619272559.png) 226 | 227 | [![1559224720528](../../images/1559224720528-1565619704251.png)](https://github.com/xiantang/Java-BackEnd-Notes/blob/master/doc/images/1559224720528.png) 228 | 229 | Receive window : 这个参数指的是滑动窗口的长度 230 | 231 | 序号 sequence number:指的是这个段中的数据的第一个字节 占在第几个位置 232 | 233 | 确认号 acknowledgement number: 发送当前收到的有序的数据包在对面的位置+1 234 | 235 | 偏移量 head len: TCP 数据 是从多少个字节之后开始的 因为TCP 数据包是除了20字节的首部 还有一定的长度 所以头部是可变长的 236 | 237 | S: SYN 建立连线 238 | 239 | F: FIN 连线完成 240 | 241 | R: RST 关闭连线 就像点击浏览器的×一样 一方关闭连接 242 | 243 | ![1565703106108](../../images/1565703106108.png) 244 | 245 | ### 246 | 247 | 248 | 249 | SYN: 发起一个链接 250 | 251 | ![img](../../images/d8bf92c7906718271fdb8b0d2d5fe5b4) 252 | 253 | 1. 发送SYN为1的segment到服务器 254 | * 确定初始化的seq 255 | * 不需要data 256 | 2. 接受SYN 257 | * 申请buffers 258 | * 确定server的初始化seq 259 | 3. 客户端收到SYNACK。还要再回复一个ACK,但是这个封包可能含有数据。 260 | 261 | ![img](../../images/191918-81271b7d3443a160.webp) 262 | 263 | 264 | 265 | TCP 传输数据 客户端发送 SEQ 和 100 byte 的数据 服务端收到 并且将ACK number 设置成 SEQ + 100 byte +1 表示这个ack number 之前的数据都已经收到了。 266 | 267 | 268 | 269 | #### TCP 连接管理 270 | 271 | 272 | 273 | **客户端结束**: 274 | 275 | 276 | 277 | ![1559283754130](../../images/1559283754130.png) 278 | 279 | 280 | 281 | 一个connection 有两个buffer 分别是sender的和receiver的。 282 | 283 | 为什么TCP为什么是四次挥手? 284 | 285 | 因为是全双工通信的 286 | 287 | 1. 第一次挥手发送fin 表示主动方不会再继续发送报文了,但是可以发送报文 288 | 2. 第二次挥手被动方可能有相应的数据报文需要发送,需要发送ACK,告诉主动方我知道你要断开请求了 289 | 3. 第三次挥手被动方在处理完数据报文后,便发送给主动方FIN报文;这样可以保证数据通信正常可靠地完成。发送完FIN报文后,被动方进入LAST_ACK阶段(超时等待)。 290 | 4. 如果主动方及时发送ACK报文进行连接中断的确认,这时被动方就直接释放连接,进入可用状态。 291 | 292 | 为什么要等2MSL ? 293 | 294 | * ack 是 主动端发送的是吧 然后 服务器不一定能收到这个ack 如果收不到服务器就会重发一个FIN-ACK回去 这就是两个RTT MSL 大于一个RTT 295 | * 防止重发的数据骚扰服务端 296 | 297 | ### 2.flow control 流量控制 298 | 299 | 300 | 301 | ![1559282483503](../../images/1559282483503.png) 302 | 303 | 流量控制指的是 sender 不要把 receiver 塞爆。 304 | 305 | sender 能送多少的数据取决于接受端RevWindow 的大小 306 | 307 | 这个的大小会存储在segment的字段中。 308 | 309 | receiver 来控制sender 送的频率,如果不想让sender 送数据那么就将传送过去的window的大小设置为0。 310 | 311 | 如果发送端收到一个 rwnd 的长度为0的ACK 并且一直在等待,但是接收方一直不发送长度不为0的ACK 过来索要数据,发送端需要发送一个心跳包确保连接是否还建立。 312 | 313 | ### 3.拥塞控制 314 | 315 | * 定义:分组交换网络中传送分组的数目太多时,由于存储转发节点的资源有限而造成网络传输性能下降的情况。 316 | 317 | * 现象: 318 | * 掉封包 319 | * 封包queue中,很长时间的延迟 320 | 321 | * 解决方式: 322 | * 根据自己手上有的资讯进行判断 323 | * 根据路由器的埋点进行通知发送方 324 | 325 | 但是TCP 主要采用的是通过两端的发送方和接受方的进行判断的。 326 | 327 | 328 | 329 | **AIMD** 330 | 331 | ![1565708534295](../../images/1565708534295.png) 332 | 333 | 首先探测网络的频宽有多大,所以他会越送越快,直到掉落分包为止。 334 | 335 | * 每一个RTT时间就增加一个MSS(最大segment的大小) ,每个RTT 直到丢失封包 336 | * 减少一半的**CongWin** 337 | 338 | ![img](../../images/1234352-e9c36c1963b96e3b.webp) 339 | $$ 340 | rate = \frac{CongWin}{RTT} Bytes/sec 341 | $$ 342 | ##### 慢开始 343 | 344 | 一开始比较慢,然后指数增长 CongWin 的大小,也就是MSS的数目。 345 | 346 | 当连接开始的时候,提升每个 RTT 发送的 CongWin 的大小。 347 | 348 | - 收到ACK的时候提升两倍CongWin的大小,也是就是两倍的segment的数目。 349 | 350 | 351 | 352 | 353 | 354 | ##### 快重传 355 | 356 | ![1565712724516](../../images/1565712724516.png) 357 | 358 | B 收到1 2 4 个包 这时 3 就被确认为挂了 359 | 360 | 我们就将直接发送3 个 3 的ACK 发现丢包立刻让A重发 361 | 362 | 推断丢包 363 | 364 | - 收到3个重复的ACK 365 | - CongWin cut 一半 366 | - 线性增加CongWin的大小 367 | - 直接进入 加法增加 368 | - 发生timeout 369 | - CongWin 替换为 1MSS 370 | - window 先指数增长 371 | - 到达临界值的时候线性增长 372 | 373 | ![img](../../images/1234352-2738b3eb14207b1c.webp) 374 | 375 | 376 | 377 | #### 总结 378 | 379 | * 双向的连接 380 | * 每个seq的单位是1byte 381 | * 根据流量控制和拥塞控制来决定窗口的大小 382 | 383 | 384 | 385 | 386 | 387 | ## 网络层 388 | 389 | ### 网络层最重要的两个服务 390 | 391 | 负责在网络之间尽力转发数据包,基于数据包的ip地址转发 392 | 393 | 不负责丢失重传 不负责顺序 394 | 395 | * 转发:将一个封包从一个路由器转发到最合适的出口路由器 396 | * 路由:决定你的封包的起点到终点的路径 397 | 398 | ### ARP 协议: 399 | 400 | 对于一个ip 我们先判断是否是当前网段,根据子网掩码 401 | 402 | 在根据子网掩码判断目标地址在哪个网段 403 | 404 | 如果是同一个网段 就使用arp解析目标地址ip地址的MAC 405 | 406 | 如果是当前网段就向前面发送一个广播包,交换机遇到这个广播包就会发送这个全为1的包,被动方回应主机的MAC地址 407 | 408 | 计算机要想跨网段通讯必须得配网关 409 | 410 | ### 无连接的服务 411 | 412 | #### Datagram networks 413 | 414 | * 不需要建立连接 415 | * 不需要记录之前的路径 416 | * 根据查表走路径 417 | 418 | 419 | 420 | **转发表**: 421 | 422 | 前缀匹配: 只要知道前面的bit数目,就可以知道对应的Link interface 423 | 424 | ![1559307942030](../../images/1559307942030.png) 425 | 426 | 当好几个项都匹配的时候,去到那个最长的匹配的接口。 427 | 428 | #### IP datagram format 429 | 430 | ![1559310072992](../../images/1559310072992.png) 431 | 432 | 433 | 434 | * offset:封包对于原来封包所在的位置 435 | * 16-bit identifien:确定是哪个segment 436 | 437 | 438 | 439 | #### Subnets 440 | 441 | 可以直接沟通不通过其他路由器 442 | 443 | * subnet part(高位bit) 444 | * host part(低位bit) 445 | 446 | 447 | 448 | ### IPv6 449 | 450 | #### Header(Cont) 451 | 452 | ![1559741999036](../../images/1559741999036.png) 453 | 454 | * Checksum: 从IPV4 中去掉了 455 | * ICMPv6: 封包太大的异常 群播 456 | 457 | #### 转移 IPv4->IPv6 458 | 459 | 隧道:IPv6的封包放到IPv4里面 460 | 461 | ![1559742437450](../../images/1559742437450.png) 462 | 463 | 其实就是将V6的封包包在V4中而已 464 | 465 | ![1559742541710](../../images/1559742541710.png) 466 | 467 | -------------------------------------------------------------------------------- /doc/notes/scala/akka 源码.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```scala 4 | object Main1 extends App { 5 | val system = ActorSystem("HelloSystem") 6 | val jazzListener = system.actorOf(Props[Listener]) 7 | val musicListener = system.actorOf(Props[Listener]) 8 | system.eventStream.subscribe(jazzListener, classOf[Jazz]) // jazzListener 订阅 Jazz 事件 9 | system.eventStream.subscribe(musicListener, classOf[AllKindsOfMusic]) // musicListener 订阅 AllKindsOfMusic 以及它的子类 事件 10 | 11 | // 只有 musicListener 接收到这个事件 12 | system.eventStream.publish(Electronic("Parov Stelar")) 13 | 14 | // jazzListener 和 musicListener 都会收到这个事件 15 | system.eventStream.publish(Jazz("Sonny Rollins")) 16 | } 17 | 18 | ``` 19 | 20 | ## subscribe 逻辑 21 | 22 | 同步地将 subcriber 和 to 加入到 subscriptions 中,diff 应该是和之前的一次比较保证不会重复发送? 23 | 24 | ```scala 25 | def subscribe(subscriber: Subscriber, to: Classifier): Boolean = subscriptions.synchronized { 26 | val diff = subscriptions.addValue(to, subscriber) 27 | addToCache(diff) 28 | diff.nonEmpty 29 | } 30 | ``` 31 | 32 | ![image-20200109114040999](/Users/xiantang/Library/Application Support/typora-user-images/image-20200109114040999.png) 33 | 34 | ![image-20200109131215939](/Users/xiantang/Library/Application Support/typora-user-images/image-20200109131215939.png) 35 | 36 | addValue 中有个比较重要的方法,就是从 `subkeys` 也就是 subscribe 中到找对应的类。 37 | 38 | 可以将`subkeys` 想象为一个多叉树中的一个节点,节点的key为订阅源类型,value为所对应的订阅者 Actor 39 | 40 | 然后这个节点也有自己的`subkeys` 这些subkeys 为的key为上层类型的子类,同时订阅者是与是上层订阅者的拓展 41 | 42 | ![image-20200109140449787](/Users/xiantang/Library/Application Support/typora-user-images/image-20200109140449787.png) 43 | 44 | 对于重复的订阅,他会做一次去重,类似于arc diff 45 | 46 | 对于 ` system.eventStream.subscribe(jazzListener, classOf[Jazz])` 47 | 48 | ![image-20200109120145086](/Users/xiantang/Library/Application Support/typora-user-images/image-20200109120145086.png) 49 | 50 | 会产生一个这样的diff 然后加入到cache 中 51 | 52 | cache 的数据结构是一个 `private var cache = Map.empty[Classifier, Set[Subscriber]]` Map 分别是订阅源和订阅者 53 | 54 | 对于 `system.eventStream.subscribe(musicListener, classOf[AllKindsOfMusic]) ` 55 | 56 | ![image-20200109120406852](/Users/xiantang/Library/Application Support/typora-user-images/image-20200109120406852.png) 57 | 58 | 59 | 60 | 61 | 62 | ## publish 逻辑 63 | 64 | ```scala 65 | def publish(event: Event): Unit = { 66 | val c = classify(event) 67 | val recv = 68 | if (cache contains c) cache(c) // c will never be removed from cache 69 | else 70 | subscriptions.synchronized { 71 | if (cache contains c) cache(c) 72 | else { 73 | addToCache(subscriptions.addKey(c)) 74 | cache(c) 75 | } 76 | } 77 | recv.foreach(publish(event, _)) 78 | } 79 | ``` 80 | 81 | publish 逻辑较为简单,首先会从event中找出对应 className 82 | 83 | 然后走缓存逻辑,如果不在缓存中存在,就将对应的 key 更新到subkeys 多叉树中,找到对应的订阅者,并且更新到cache 中。 84 | 85 | 最后遍历 recv 调用publish函数 。 86 | 87 | ```scala 88 | protected def publish(event: Any, subscriber: ActorRef) = { 89 | if (sys == null && subscriber.isTerminated) unsubscribe(subscriber) 90 | else subscriber ! event 91 | } 92 | ``` 93 | 94 | 95 | 96 | 97 | 98 | # Actor 初始化 99 | 100 | ```scala 101 | val pinger = system.actorOf(Props[Pinger], "pinger") 102 | val ponger = system.actorOf(Props(classOf[Ponger], pinger), "ponger") 103 | ``` 104 | 105 | 会调用 ActorSystem 中的actorOf方法 106 | 107 | ```scala 108 | def actorOf(props: Props): ActorRef = 109 | if (guardianProps.isEmpty) guardian.underlying.attachChild(props, systemService = false) 110 | else 111 | throw new UnsupportedOperationException( 112 | "cannot create top-level actor from the outside on ActorSystem with custom user guardian") 113 | ``` 114 | 115 | 会从守卫Actor 下面创建一个新的Child Actor 116 | 117 | 会调用下边的makeChild 方法: 118 | 119 | Children.scala 120 | 121 | ```scala 122 | val actor = 123 | try { 124 | val childPath = new ChildActorPath(cell.self.path, name, ActorCell.newUid()) 125 | cell.provider.actorOf( 126 | cell.systemImpl, 127 | props, 128 | cell.self, 129 | childPath, 130 | systemService = systemService, 131 | deploy = None, 132 | lookupDeploy = true, 133 | async = async) 134 | } 135 | 136 | initChild(actor) 137 | actor.start() // 绑定 actor 到 dispatcher 138 | actor // 返回 actor ref 139 | ``` 140 | 141 | 142 | 143 | ## Tell 实现 144 | 145 | ```scala 146 | final def sendMessage(message: Any, sender: ActorRef): Unit = 147 | sendMessage(Envelope(message, sender, system)) 148 | ``` 149 | 150 | 将message 包装为信封,调用Cell 的 sendMessage 方法 151 | 152 | 是因为 Cell 实现了 153 | 154 | ![image-20200109195143660](/Users/xiantang/Library/Application Support/typora-user-images/image-20200109195143660.png) 155 | 156 | Dispatch 特质 157 | 158 | 其实是执行的 Dispatch 特质中的 sendMessage 方法 159 | 160 | ```scala 161 | def sendMessage(msg: Envelope): Unit = 162 | try { 163 | val msgToDispatch = 164 | if (system.settings.SerializeAllMessages) serializeAndDeserialize(msg) 165 | else msg 166 | 167 | dispatcher.dispatch(this, msgToDispatch) 168 | } catch handleException 169 | ``` 170 | 171 | 但是我仍然有个问题,dispatcher 是我自己规定的dispather ? 172 | 173 | 再调用这个Actor 所对应的 dispatcher 的 dispatch 函数 174 | 175 | ```scala 176 | protected[akka] def dispatch(receiver: ActorCell, invocation: Envelope): Unit = { 177 | val mbox = receiver.mailbox 178 | mbox.enqueue(receiver.self, invocation) 179 | registerForExecution(mbox, true, false) 180 | } 181 | ``` 182 | 183 | 将信封丢入对应接收者的 mailbox 中,然后将 mbox 作为参数传入 registerForExecution 注册到线程池中。 184 | 185 | 而这个线程池就是我预设的线程池, dispacher 只是对这个线程池做一层封装。 186 | 187 | ```scala 188 | protected[akka] override def registerForExecution( 189 | mbox: Mailbox, 190 | hasMessageHint: Boolean, 191 | hasSystemMessageHint: Boolean): Boolean = { 192 | if (mbox.canBeScheduledForExecution(hasMessageHint, hasSystemMessageHint)) { //This needs to be here to ensure thread safety and no races 193 | if (mbox.setAsScheduled()) { 194 | try { 195 | //!!!! 196 | executorService.execute(mbox) 197 | true 198 | } catch { 199 | ... 200 | } 201 | } else false 202 | } else false 203 | } 204 | ``` 205 | 206 | 使用内部的线程池来执行这个 MailBox 对象 207 | 208 | 既然 MailBox 可以被执行 它一定实现了 Runnable 方法 来看看他的实现: 209 | 210 | ```scala 211 | override final def run(): Unit = { 212 | try { 213 | if (!isClosed) { //Volatile read, needed here 214 | processAllSystemMessages() //First, deal with any system messages 215 | processMailbox() //Then deal with messages 216 | } 217 | } finally { 218 | setAsIdle() //Volatile write, needed here 219 | dispatcher.registerForExecution(this, false, false) 220 | } 221 | } 222 | ``` 223 | 224 | 来主要看一下 processMailbox 方法的实现吧 225 | 226 | ```scala 227 | @tailrec private final def processMailbox( 228 | left: Int = java.lang.Math.max(dispatcher.throughput, 1), 229 | deadlineNs: Long = 230 | if (dispatcher.isThroughputDeadlineTimeDefined) 231 | System.nanoTime + dispatcher.throughputDeadlineTime.toNanos 232 | else 0L): Unit = 233 | if (shouldProcessMessage) { 234 | val next = dequeue() 235 | if (next ne null) { 236 | if (Mailbox.debug) println(actor.self + " processing message " + next) 237 | actor.invoke(next) 238 | if (Thread.interrupted()) 239 | throw new InterruptedException("Interrupted while processing actor messages") 240 | processAllSystemMessages() 241 | if ((left > 1) && (!dispatcher.isThroughputDeadlineTimeDefined || (System.nanoTime - deadlineNs) < 0)) 242 | processMailbox(left - 1, deadlineNs) 243 | } 244 | } 245 | ``` 246 | 247 | 248 | 249 | 很简单的实现,使用了尾递归的方式, 250 | 251 | 1. 首先计算出 left 也就是分发器的吞吐量 252 | 2. 然后从队列里面出队一个元素 253 | 3. 调用actor 的invoke 方法 254 | 4. 继续向下调用直到 left <1 或者 255 | 256 | 有两个关键的参数, 257 | 258 | throughput 也就是单次执行 `executorService.execute(mbox)` 所消费消息的数量。超出这个数量的消息将会交给下次执行这个 mbox 的时候执行。 259 | 260 | `deadlineNs` 发送throughput数量消息的截止时间,保证throughput的消息要在截止时间内完成。 261 | 262 | 调用 actor 的 invoke 方法下面会调用 ActorCell 的 receiveMessage 方法 263 | 264 | `actor.aroundReceive(behaviorStack.head, msg)` 265 | 266 | 获得栈顶的 Receive 偏函数,调用 aroundReceive 来执行操作 267 | 268 | ```scala 269 | protected[akka] def aroundReceive(receive: Actor.Receive, msg: Any): Unit = { 270 | // optimization: avoid allocation of lambda 271 | if (receive.applyOrElse(msg, Actor.notHandledFun).asInstanceOf[AnyRef] eq Actor.NotHandled) { 272 | unhandled(msg) 273 | } 274 | } 275 | ``` 276 | 277 | 如果receive 没有match对应的message,使用了偏函数的 applyOrElse 捕获剩下的值域,判断返回值是否和 NotHandled 相等。 278 | 279 | ```scala 280 | def unhandled(message: Any): Unit = { 281 | message match { 282 | case Terminated(dead) => throw DeathPactException(dead) 283 | case _ => context.system.eventStream.publish(UnhandledMessage(message, sender(), self)) 284 | } 285 | } 286 | ``` 287 | 288 | 对message 做一次模式匹配,如果是没有handle的message 就将它作为订阅发出。 289 | 290 | 这里我们可以使用一个订阅者 `system.eventStream.subscribe(listener, classOf[UnhandledMessage]) ` 来订阅这些消息,进行日志输出。 --------------------------------------------------------------------------------