├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── architecture
├── 2PC-3PC.md
├── README.md
├── design_patterns.md
├── elasticSearch.md
├── img
│ ├── aggregation.png
│ ├── association.png
│ ├── combine.png
│ ├── depend.png
│ ├── extends.png
│ ├── implement.png
│ ├── uml-class-animal.jpg
│ └── uml-object.jpg
├── mysql.md
├── pom.xml
├── redis.md
├── src
│ └── main
│ │ └── java
│ │ └── cn
│ │ └── tommyyang
│ │ └── designpatterns
│ │ ├── duckgame
│ │ ├── Duck.java
│ │ ├── MainExecutor.java
│ │ ├── MallardDuck.java
│ │ ├── RedheadDuck.java
│ │ ├── RubberDuck.java
│ │ ├── WoodDuck.java
│ │ └── behavior
│ │ │ ├── FlyBehavior.java
│ │ │ ├── QuackBehavior.java
│ │ │ └── impl
│ │ │ ├── FlyWithNoWay.java
│ │ │ ├── FlyWithWay.java
│ │ │ ├── FlyWithWings.java
│ │ │ ├── MuteQuack.java
│ │ │ ├── Quack.java
│ │ │ └── Squeak.java
│ │ └── observable
│ │ ├── WeatherData.java
│ │ └── display
│ │ └── CurrentConditionsDisplay.java
└── uml.md
├── bigdata
├── README.md
├── hadoop.md
├── hive.md
├── hive_udf.md
├── kafka_1.md
├── maxlist_set.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── cn
│ └── tommyyang
│ ├── bigfile
│ ├── BigFile.java
│ ├── fileservice
│ │ └── FileService.java
│ └── utils
│ │ ├── BigFileTool.java
│ │ ├── IHandle.java
│ │ └── MultiThreadReader.java
│ ├── collections
│ ├── ListUtils.java
│ └── RunTest.java
│ └── hive
│ └── udf
│ ├── ContainsString.java
│ └── IPToLocation.java
├── books
└── README.md
├── codeinterview
├── README.md
├── dynamic-programming.md
├── order-print-num.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── cn
│ └── tommyyang
│ ├── array
│ ├── FindPosition.java
│ ├── InterSection.java
│ └── TwoSortArrMerge.java
│ ├── listnode
│ ├── CrossLinkedList.java
│ ├── CycleNode2.java
│ ├── DeleteNodeInLinkedList.java
│ ├── DetectCycle.java
│ ├── HasCycle.java
│ ├── ListNode.java
│ ├── MergeTwoSortLinkedList.java
│ ├── RemoveElementsInLinkedList.java
│ ├── RemoveNthFromEnd.java
│ ├── ReverseLinkedList.java
│ └── ReverseLinkedList2.java
│ ├── multithread
│ └── OrderPrintNum.java
│ ├── str
│ ├── LongestSubstring.java
│ └── ReverseInt.java
│ └── tree
│ ├── InvertTree.java
│ ├── MergeTwoBTree.java
│ ├── TreeNode.java
│ └── ValidBST.java
├── img
└── AB测试.png
├── io
├── Multi-Thread-Write-File.md
├── README.md
├── Thread-CPU-Process.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── cn
│ └── tommyyang
│ ├── aio
│ ├── AcceptCompletionHandler.java
│ ├── AsyncTimeClientHandler.java
│ ├── AsyncTimeServerHandler.java
│ ├── ReadCompletionHandler.java
│ ├── TimeClient.java
│ └── TimeServer.java
│ ├── file
│ ├── BigFileWriter.java
│ ├── BigFileWriter1.java
│ ├── FileTest.java
│ └── FileUtils.java
│ ├── nettynio
│ ├── TimeClient.java
│ ├── TimeClientHandler.java
│ ├── TimeServer.java
│ └── TimeServerHandler.java
│ └── nio
│ ├── MultiplexerTimeServer.java
│ ├── TimeClient.java
│ ├── TimeClientHandler.java
│ └── TimeServer.java
├── javabase
├── README.md
├── datastructure
│ ├── README.md
│ ├── blockingqueueanddeque.md
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── cn
│ │ └── tommyyang
│ │ ├── RunTest.java
│ │ ├── forkjoinpool
│ │ └── CountTask.java
│ │ ├── queue
│ │ └── ArrayBlockingQueueDemo.java
│ │ └── string
│ │ └── StringTest.java
├── exception.md
├── img
│ └── exception_category.png
├── java8
│ ├── README.md
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── cn
│ │ └── tommyyang
│ │ ├── functioninterface
│ │ ├── ApplePredicate.java
│ │ ├── DefaultInterface.java
│ │ ├── Demo.java
│ │ ├── Predicate.java
│ │ └── ProgressDemo.java
│ │ ├── model
│ │ ├── Apple.java
│ │ ├── Fruit.java
│ │ └── Pear.java
│ │ └── streamapi
│ │ ├── CountService.java
│ │ └── StreamAPI.java
├── keywords
│ ├── README.md
│ ├── pom.xml
│ ├── res
│ │ ├── transient.png
│ │ └── transienttest.txt
│ ├── src
│ │ └── main
│ │ │ └── java
│ │ │ ├── transientkey
│ │ │ └── TransientTest.java
│ │ │ └── volatilekey
│ │ │ ├── ordering
│ │ │ ├── AThread.java
│ │ │ ├── BThread.java
│ │ │ ├── Model.java
│ │ │ └── RunTest.java
│ │ │ ├── unsafe
│ │ │ ├── Counter.java
│ │ │ ├── OwnUnSafe.java
│ │ │ ├── Runtest.java
│ │ │ └── ThreadCommunicate.java
│ │ │ └── visibility
│ │ │ └── RunTest.java
│ ├── transient.md
│ └── volatile.md
├── stringbuilderandstringbuffer.md
└── threadpool.md
├── jvm
├── README.md
├── garbage_collectors.md
└── jvm_params.md
├── lock
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── cn
│ └── tommyyang
│ ├── demo
│ ├── RunTest.java
│ └── lock
│ │ ├── Consumer.java
│ │ ├── Producer.java
│ │ ├── ReentrantLockDemo.java
│ │ └── SynchronizedDemo.java
│ └── distributedlock
│ └── RedisDistributedLock.java
├── machinelearning
├── model.md
├── recommend_system.md
└── tensorflow.md
├── mymp.jpeg
├── pom.xml
├── sortpro
├── 1.bubbleSort.md
├── 10.radixSort.md
├── 2.selectionSort.md
├── 3.insertionSort.md
├── 4.shellSort.md
├── 5.mergeSort.md
├── 6.quickSort.md
├── 7.heapSort.md
├── 8.countingSort.md
├── 9.bucketSort.md
├── README.md
├── pom.xml
├── res
│ ├── bubbleSort.gif
│ ├── countingSort.gif
│ ├── heapSort.gif
│ ├── insertionSort.gif
│ ├── mergeSort.gif
│ ├── quickSort.gif
│ ├── radixSort.gif
│ ├── selectionSort.gif
│ └── sort.png
└── src
│ └── main
│ └── java
│ ├── Run.java
│ ├── search
│ └── BinarySearch.java
│ └── sort
│ ├── BubbleSort.java
│ ├── BucketSort.java
│ ├── CountingSort.java
│ ├── HeapSort.java
│ ├── IArraySort.java
│ ├── InsertSort.java
│ ├── MergeSort.java
│ ├── QuickSort.java
│ ├── QuickSort1.java
│ ├── RadixSort.java
│ ├── SelectionSort.java
│ └── ShellSort.java
├── test
├── pom.xml
└── src
│ └── main
│ ├── java
│ ├── HiveTableChange.java
│ ├── StringUitls.java
│ ├── Test.java
│ ├── cn
│ │ └── tommyyang
│ │ │ ├── demo
│ │ │ └── Person.java
│ │ │ └── grpc
│ │ │ ├── GrpcClient.java
│ │ │ ├── GrpcServer.java
│ │ │ └── protobuf
│ │ │ ├── GreeterGrpc.java
│ │ │ └── GreeterOuterClass.java
│ └── demo
│ │ ├── Demo1.java
│ │ ├── Event.java
│ │ └── TreeNode.java
│ └── protos
│ └── greeter.proto
└── web
├── POJO、BO、VO、DO、DTO、DAO、PO etc.md
├── README.md
├── filter-interceptor.md
├── http-processing.md
├── pom.xml
├── spring-config.md
├── spring-ioc.md
└── spring.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | classes
3 | _data
4 | target
5 | .idea
6 | *.prefs
7 | *.project
8 | *.classpath
9 | *.rar
10 | .settings
11 | *.iml
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | language: java
3 |
4 | jdk:
5 | # - oraclejdk8
6 | - openjdk8
7 |
8 | ignore:
9 | - *.md
10 | - .gitignore
11 | - LICENSE
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Java 知识总结
2 | [](https://travis-ci.org/joyang1/JavaInterview)
3 | [](http://makeapullrequest.com)
4 |
5 | **该项目主要分享一些个人经验,以及一些个人项目中遇到的问题**;还有就是一些读书笔记。
6 |
7 | 如果大家觉得该项目还不错,可以帮忙 `star` 或者 fork 下,你的 `star` 就是我的动力,谢谢!
8 |
9 | **为开源贡献自己的一份力量。**
10 |
11 | ## :blue_book: [JVM 篇](/jvm)
12 |
13 | ## :coffee: [Java 基础知识篇](/javabase)
14 |
15 | ## :scroll: [代码篇](/codeinterview)
16 | 主要介绍 LeetCode 上面的算法题目,以及面试过程中遇到的实际编码问题总结。
17 |
18 | ### [排序相关](/sortpro)
19 | - [冒泡排序](/sortpro/1.bubbleSort.md)
20 | - [选择排序](/sortpro/2.selectionSort.md)
21 | - [插入排序](/sortpro/3.insertionSort.md)
22 | - [希尔排序](/sortpro/4.shellSort.md)
23 | - [归并排序](/sortpro/5.mergeSort.md)
24 | - [快速排序](/sortpro/6.quickSort.md)
25 | - [堆排序](/sortpro/7.heapSort.md)
26 | - [计数排序](/sortpro/8.countingSort.md)
27 | - [桶排序](/sortpro/9.bucketSort.md)
28 | - [基数排序](/sortpro/10.radixSort.md)
29 |
30 | ## :lock: [Lock 篇](/lock)
31 |
32 | ## :file_folder: [IO 篇](/io)
33 |
34 | ## :computer: [大数据篇](/bigdata)
35 |
36 | ## :earth_asia: [机器学习](/machinelearning)
37 |
38 | ## :floppy_disk: [架构篇](/architecture)
39 |
40 | ## :earth_asia: [web 篇](/web)
41 |
42 | ## :books: [书单篇](/books)
43 | 各种编程类书籍整理。大家可以直接下载阅读,增长自己编程技术。
44 |
45 |
46 | # Author
47 | 联系我:tingzai.yang@gmail.com
48 |
49 | [个人博客](https://blog.tommyyang.cn)
50 |
51 | 有任何问题,或者好的建议,好的面试相关的题目都可以在这里面进行提交!
52 |
53 | 有什么问题也可以在这里进行[讨论](https://github.com/joyang1/JavaInterview/issues/1)。
54 |
55 | **欢迎关注个人公众号,每天更新原创技术好文**:
56 |
57 | 
58 |
59 |
--------------------------------------------------------------------------------
/architecture/README.md:
--------------------------------------------------------------------------------
1 | # 架构篇
2 |
3 | ## UML图
4 | 分享项目设计中需要的类图、对象图、时序图等。
5 | [UML图总结](uml.md)
6 |
7 | ## 设计模式
8 | 分享实际项目中的设计模式经验。
9 | [设计模式](design_patterns.md)
10 |
11 | ## 分布式
12 |
13 | ### 分布式一致性问题
14 | 1. 分布式一致性理论
15 | - [2PC-3PC](2PC-3PC.md)
16 | - Paxos 理论
17 | - CAP 理论
18 |
19 | 2. Raft协议(etcd)
20 | 4. zookeeper在分布式中的应用
21 | 5. 金融方面: 任务补偿,最终一致性
22 |
23 | ## 微服务
24 |
25 | ## 大型网站架构
26 |
27 | ## 流行数据库架构
28 | - [MySQL](mysql.md)
29 | - [Redis](redis.md)
30 | - [ElasticSearch](elasticSearch.md)
31 | - MongoDB
32 |
33 | ## 大数据
34 | - Hadoop
35 | - Hive
36 | - Spark
37 |
38 | ## 推荐系统
39 | - [推荐系统](recommend_system.md)
40 |
--------------------------------------------------------------------------------
/architecture/img/aggregation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/architecture/img/aggregation.png
--------------------------------------------------------------------------------
/architecture/img/association.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/architecture/img/association.png
--------------------------------------------------------------------------------
/architecture/img/combine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/architecture/img/combine.png
--------------------------------------------------------------------------------
/architecture/img/depend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/architecture/img/depend.png
--------------------------------------------------------------------------------
/architecture/img/extends.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/architecture/img/extends.png
--------------------------------------------------------------------------------
/architecture/img/implement.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/architecture/img/implement.png
--------------------------------------------------------------------------------
/architecture/img/uml-class-animal.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/architecture/img/uml-class-animal.jpg
--------------------------------------------------------------------------------
/architecture/img/uml-object.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/architecture/img/uml-object.jpg
--------------------------------------------------------------------------------
/architecture/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | javainterview
7 | cn.tommyyang
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | architecture
13 |
14 |
15 |
--------------------------------------------------------------------------------
/architecture/redis.md:
--------------------------------------------------------------------------------
1 | # Redis
2 | Redis 作为一种 KV 缓存服务器,有着极高的性能,相对于 Memcache,Redis 支持更多种数据类型,因此在业界应用广泛。
3 |
4 | ## 性能高的原因
5 | - 纯内存操作
6 | - 单线程
7 | - 高效的数据结构
8 | - 合理的数据编码
9 | - 其他方面的优化
10 |
11 | ## 适用场景
12 | 在 Redis 中,常用的 5 种数据结构和应用场景如下:
13 |
14 | - String:缓存、计数器、分布式锁等。
15 | - List:链表、队列、微博关注人时间轴列表等。
16 | - Hash:用户信息、Hash 表等。
17 | - Set:去重、赞、踩、共同好友等。
18 | - ZSet:访问量排行榜、点击量排行榜等。
19 |
20 | ## 数据结构分析
21 |
22 | ### SDS
23 |
24 | ### 字典
25 |
26 | ### 跳跃表
27 |
28 | ### List
29 |
30 | ### Set
31 |
32 | ### ZSet
33 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/Duck.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior;
4 | import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior;
5 |
6 | /**
7 | * 鸭子超类(抽象类)
8 | *
9 | * @Author : TommyYang
10 | * @Time : 2021-04-05 15:57
11 | * @Software: IntelliJ IDEA
12 | * @File : Duck.java
13 | */
14 | public abstract class Duck {
15 |
16 | public Duck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
17 | this.flyBehavior = flyBehavior;
18 | this.quackBehavior = quackBehavior;
19 | }
20 |
21 | /**
22 | * 名称
23 | */
24 | private String name;
25 |
26 | /**
27 | * 飞行行为
28 | */
29 | private FlyBehavior flyBehavior;
30 |
31 | /**
32 | * 呱呱叫行为
33 | */
34 | private QuackBehavior quackBehavior;
35 |
36 | /**
37 | * 鸭子的叫声
38 | */
39 | public void performQuack() {
40 | this.quackBehavior.quack();
41 | }
42 |
43 | /**
44 | * 鸭子游泳
45 | */
46 | public void swim() {
47 | System.out.println("游泳");
48 | }
49 |
50 |
51 | /**
52 | * 执行飞行行为
53 | */
54 | public void performFly() {
55 | this.flyBehavior.fly();
56 | }
57 |
58 | /**
59 | * 鸭子外观都不相同,所以设计为抽象方法
60 | */
61 | public abstract void display();
62 |
63 | public void setFlyBehavior(FlyBehavior flyBehavior) {
64 | this.flyBehavior = flyBehavior;
65 | }
66 |
67 | public void setQuackBehavior(QuackBehavior quackBehavior) {
68 | this.quackBehavior = quackBehavior;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/MainExecutor.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.Duck;
4 | import cn.tommyyang.designpatterns.duckgame.RubberDuck;
5 | import cn.tommyyang.designpatterns.duckgame.WoodDuck;
6 | import cn.tommyyang.designpatterns.duckgame.behavior.impl.FlyWithNoWay;
7 | import cn.tommyyang.designpatterns.duckgame.behavior.impl.MuteQuack;
8 | import cn.tommyyang.designpatterns.duckgame.behavior.impl.Squeak;
9 |
10 | /**
11 | * 鸭子游戏执行器
12 | *
13 | * @Author : TommyYang
14 | * @Time : 2021-04-05 16:00
15 | * @Software: IntelliJ IDEA
16 | * @File : MainExecutor.java
17 | */
18 | public class MainExecutor {
19 |
20 | public static void main(String[] args) {
21 |
22 | // 实现不能飞行的橡皮鸭
23 | RubberDuck rubberDuck = new RubberDuck(new FlyWithNoWay(), new Squeak());
24 | execute(rubberDuck);
25 |
26 | // 实现不能飞也不能叫的橡皮鸭
27 | WoodDuck woodDuck = new WoodDuck(new FlyWithNoWay(), new MuteQuack());
28 | execute(woodDuck);
29 |
30 | // 后续各种鸭子实现,根据业务方的需求,设置其行为即可,行为可扩展,可复用
31 | // 这就是"策略模式",各种策略实现好,组合使用即可
32 | }
33 |
34 |
35 | /**
36 | * 鸭子游戏开始运行
37 | */
38 | private static void execute(Duck duck) {
39 | duck.display();
40 | duck.performQuack();
41 | duck.performFly();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/MallardDuck.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior;
4 | import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior;
5 |
6 | /**
7 | * 野鸭类
8 | *
9 | * @Author : TommyYang
10 | * @Time : 2021-04-05 16:00
11 | * @Software: IntelliJ IDEA
12 | * @File : MallardDuck.java
13 | */
14 | public class MallardDuck extends Duck {
15 |
16 | /**
17 | * 构造器
18 | */
19 | public MallardDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
20 | super(flyBehavior, quackBehavior);
21 | }
22 |
23 | /**
24 | * 具体实现鸭子外观
25 | */
26 | public void display() {
27 | System.out.println("绿头");
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/RedheadDuck.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior;
4 | import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior;
5 |
6 | /**
7 | * 红头鸭
8 | *
9 | * @Author : TommyYang
10 | * @Time : 2021-04-05 16:02
11 | * @Software: IntelliJ IDEA
12 | * @File : RedheadDuck.java
13 | */
14 | public class RedheadDuck extends Duck {
15 | /**
16 | * 构造器
17 | */
18 | public RedheadDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
19 | super(flyBehavior, quackBehavior);
20 | }
21 |
22 | /**
23 | * 具体实现鸭子外观
24 | */
25 | public void display() {
26 | System.out.println("红头");
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/RubberDuck.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior;
4 | import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior;
5 |
6 | /**
7 | * 橡皮鸭
8 | *
9 | * @Author : TommyYang
10 | * @Time : 2021-04-05 16:17
11 | * @Software: IntelliJ IDEA
12 | * @File : RubberDuck.java
13 | */
14 | public class RubberDuck extends Duck {
15 | /**
16 | * 构造器
17 | */
18 | public RubberDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
19 | super(flyBehavior, quackBehavior);
20 | }
21 |
22 | /**
23 | * 具体实现鸭子外观
24 | */
25 | public void display() {
26 | System.out.println("橡皮鸭");
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/WoodDuck.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior;
4 | import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior;
5 |
6 | /**
7 | * @Author : TommyYang
8 | * @Time : 2021-04-10 22:23
9 | * @Software: IntelliJ IDEA
10 | * @File : WoodDuck.java
11 | */
12 | public class WoodDuck extends Duck {
13 | /**
14 | * 构造器
15 | */
16 | public WoodDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
17 | super(flyBehavior, quackBehavior);
18 | }
19 |
20 | /**
21 | * 木头鸭外观
22 | */
23 | public void display() {
24 | System.out.println("木头鸭");
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/FlyBehavior.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame.behavior;
2 |
3 | /**
4 | * 鸭子飞行行为接口
5 | *
6 | * @Author : TommyYang
7 | * @Time : 2021-04-06 00:10
8 | * @Software: IntelliJ IDEA
9 | * @File : FlyBehavior.java
10 | */
11 | public interface FlyBehavior {
12 |
13 | /**
14 | * 定义飞行方法
15 | */
16 | void fly();
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/QuackBehavior.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame.behavior;
2 |
3 | /**
4 | * 鸭子呱呱叫行为接口
5 | *
6 | * @Author : TommyYang
7 | * @Time : 2021-04-06 00:10
8 | * @Software: IntelliJ IDEA
9 | * @File : QuackBehavior.java
10 | */
11 | public interface QuackBehavior {
12 |
13 | /**
14 | * 定义呱呱叫方法
15 | */
16 | void quack();
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithNoWay.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame.behavior.impl;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior;
4 |
5 | /**
6 | * 不能飞行行为定义
7 | *
8 | * @Author : TommyYang
9 | * @Time : 2021-04-10 22:16
10 | * @Software: IntelliJ IDEA
11 | * @File : FlyWithNoWay.java
12 | */
13 | public class FlyWithNoWay implements FlyBehavior {
14 | /**
15 | * 不能飞行行为实现
16 | */
17 | @Override
18 | public void fly() {
19 | System.out.println("no way to fly");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithWay.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame.behavior.impl;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior;
4 |
5 | /**
6 | * 实现飞行方法
7 | *
8 | * @Author : TommyYang
9 | * @Time : 2021-04-07 23:23
10 | * @Software: IntelliJ IDEA
11 | * @File : FlyWithWay.java
12 | */
13 | public class FlyWithWay implements FlyBehavior {
14 | /**
15 | * 实现飞行行为
16 | */
17 | @Override
18 | public void fly() {
19 | System.out.println("fly with way");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithWings.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame.behavior.impl;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior;
4 |
5 | /**
6 | * 通过翅膀飞行实现类
7 | *
8 | * @Author : TommyYang
9 | * @Time : 2021-04-07 23:21
10 | * @Software: IntelliJ IDEA
11 | * @File : FlyWithWings.java
12 | */
13 | public class FlyWithWings implements FlyBehavior {
14 | /**
15 | * 实现飞行行为
16 | */
17 | @Override
18 | public void fly() {
19 | System.out.println("fly with wings");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/MuteQuack.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame.behavior.impl;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior;
4 |
5 | /**
6 | * @Author : TommyYang
7 | * @Time : 2021-04-09 22:31
8 | * @Software: IntelliJ IDEA
9 | * @File : MuteQuack.java
10 | */
11 | public class MuteQuack implements QuackBehavior {
12 | /**
13 | * 实现 quack 方式
14 | * 不能叫
15 | */
16 | @Override
17 | public void quack() {
18 | // nothing
19 | System.out.println("no quack");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/Quack.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame.behavior.impl;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior;
4 |
5 | /**
6 | * @Author : TommyYang
7 | * @Time : 2021-04-09 22:29
8 | * @Software: IntelliJ IDEA
9 | * @File : Quack.java
10 | */
11 | public class Quack implements QuackBehavior {
12 | /**
13 | * 实现 quack 方式
14 | */
15 | @Override
16 | public void quack() {
17 | System.out.println("呱呱叫");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/Squeak.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.duckgame.behavior.impl;
2 |
3 | import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior;
4 |
5 | /**
6 | * @Author : TommyYang
7 | * @Time : 2021-04-09 22:30
8 | * @Software: IntelliJ IDEA
9 | * @File : Squeak.java
10 | */
11 | public class Squeak implements QuackBehavior {
12 | /**
13 | * 实现 quack 方式
14 | */
15 | @Override
16 | public void quack() {
17 | System.out.println("吱吱叫");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/observable/WeatherData.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.observable;
2 |
3 | import cn.tommyyang.designpatterns.observable.display.CurrentConditionsDisplay;
4 |
5 | /**
6 | * 观察者模式
7 | * WeatherData 类
8 | *
9 | * @Author : TommyYang
10 | * @Time : 2021-04-18 15:51
11 | * @Software: IntelliJ IDEA
12 | * @File : WeatherData.java
13 | */
14 | public class WeatherData {
15 | /**
16 | * 温度
17 | */
18 | private float temperature;
19 |
20 | /**
21 | * 湿度
22 | */
23 | private float humidity;
24 |
25 | /**
26 | * 气压
27 | */
28 | private float pressure;
29 |
30 | public float getTemperature() {
31 | return this.temperature;
32 | }
33 |
34 | public float getHumidity() {
35 | return this.humidity;
36 | }
37 |
38 | public float getPressure() {
39 | return pressure;
40 | }
41 |
42 | /**
43 | * 一旦气象测量更新,此方法会被调用
44 | */
45 | public void measurementsChanged() {
46 | float temp = getTemperature();
47 | float humidity = getHumidity();
48 | float pressure = getPressure();
49 |
50 | // 布告板数据更新
51 | // 针对具体的实现编程,导致后续增删布告板时必须修改程序
52 | CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay();
53 | currentConditionsDisplay.update(temp, humidity, pressure);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/architecture/src/main/java/cn/tommyyang/designpatterns/observable/display/CurrentConditionsDisplay.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.designpatterns.observable.display;
2 |
3 | /**
4 | * @Author : TommyYang
5 | * @Time : 2021-04-18 16:00
6 | * @Software: IntelliJ IDEA
7 | * @File : CurrentConditionsDisplay.java
8 | */
9 | public class CurrentConditionsDisplay {
10 |
11 | public void update(float temp, float humidity, float pressure) {
12 |
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/architecture/uml.md:
--------------------------------------------------------------------------------
1 | # UML 图总结
2 | ## UML 类图
3 | > 描述类、接口、协作及他们之间的关系的图。显示系统中类的静态结构。
4 |
5 | ### 有什么作用?
6 | 描述软件系统的静态结构
7 | - 对系统的词汇建模
8 | - 对简单协作建模
9 | - 对逻辑数据库模式建模
10 |
11 | ### 类图说明
12 | > 类名为斜体则为抽象类
类方法为斜体则为抽象方法
第一行:类名称
第二行:类属性
第三行:类方法
类/属性/方法说明:
'-' 表示私有(private)
'#'表示保护(protected)
'+'表示公开(public)
13 |
14 |
15 |
16 | ### 依赖关系
17 | > `虚线箭头`表示。
18 |
19 |
20 |
21 |
22 | ### 继承关系
23 | > `实线空心三角形箭头`表示。
24 |
25 |
26 |
27 | ### 实现关系
28 | > `虚线空心三角形箭头`表示。
29 |
30 |
31 |
32 | ### 关联关系
33 | > `实线`表示。
34 |
35 |
36 |
37 | ### 组合关系
38 | > `实线黑色菱形箭头`表示。
39 |
40 |
41 |
42 | ### 聚合关系
43 | > `实线空心菱形箭头`表示。
44 |
45 |
46 |
47 | ## UML 对象图
48 | > 显示了某一时刻的一组对象及它们之间的关系。对象图可被看作是类图的实例,用来表达各个对象在某一时刻的状态。
49 |
50 |
51 |
52 | ### 对象图说明
53 | > stu 实例名称,Student 所属类。
第一行:对象名称
第二行:实例属性具体值
54 |
55 | - stu:Student 标准表示法
56 | - :Student 匿名表示法
57 | - stu 省略类名表示法
--------------------------------------------------------------------------------
/bigdata/README.md:
--------------------------------------------------------------------------------
1 | # 大数据篇
2 |
3 | ## 集合
4 | [海量数据去重](maxlist_set.md)
5 |
6 | ## Hadoop 平台
7 | [hadoop 结构](hadoop.md)
8 | [hive 结构](hive.md)
9 | [hive-udf 讲解](hive_udf.md)
10 |
11 | ## 消息队列
12 | [Kafka 内部结构详解](kafka_1.md)
--------------------------------------------------------------------------------
/bigdata/hadoop.md:
--------------------------------------------------------------------------------
1 | # Hadoop 架构
2 |
3 | ## Hadoop 组成
4 | - HDFS
5 | - MapReduce
6 | - Yarn (2.0 版本引入)
7 |
8 | ## HDFS
9 |
10 | ## MapReduce
11 | MapReduce是一种用于大规模数据处理的编程模型和计算框架。它被广泛应用于分布式系统中,旨在提供高效、可扩展和可靠的数据处理解决方案。
12 |
13 | MapReduce的核心思想是将大规模数据集分成小的数据块,然后并行处理这些数据块。这个过程包括两个主要阶段:Map阶段和Reduce阶段。
14 |
15 | 在Map阶段,数据集被划分成多个小的输入块,每个输入块由一个Map任务处理。Map任务将输入块转换成键值对的集合。键值对的生成是通过应用用户自定义的Map函数来实现的。这个函数将输入数据转换成一个或多个键值对,其中键表示数据的特定属性,值则包含与该键相关联的信息。
16 |
17 | 在Reduce阶段,Map任务生成的键值对集合被分组和排序,然后传递给Reduce任务进行处理。Reduce任务的数量通常与计算集群中的处理节点数量相匹配。Reduce任务将相同键的键值对进行合并、计算和聚合操作,生成最终的输出结果。Reduce函数也是用户自定义的,根据需要执行各种操作,例如求和、计数、平均值等。
18 |
19 | MapReduce的优点在于它的并行性和可伸缩性。通过将数据划分成小块并将其分发给多个处理节点进行并行处理,MapReduce可以有效地处理大规模数据集,提高处理速度和性能。此外,它提供了自动处理故障和容错的机制,保证了计算的可靠性。
20 |
21 | MapReduce在分布式系统中得到了广泛应用。它是Apache Hadoop框架的核心组件之一,被用于处理大数据和进行复杂的数据分析任务。MapReduce还可以在其他领域中发挥作用,如搜索引擎、机器学习和图形处理等。
22 |
23 | 总而言之,MapReduce是一种强大的编程模型和计算框架,通过将大规模数据集划分成小块并在分布式环境中并行处理,提供了高效、可扩展和可靠的数据处理解决方案。它在大数据领域的应用前景广阔,并在多个领域中发挥着重要的作用。
24 |
25 | ## Yarn
26 |
27 |
28 | ## 例子
29 | 我们在 Hive 执行一个 select 操作需要经历的步骤。
30 | 1. 通过 HiveServer2 得到 hdfs 文件目录;
31 | 2. 向 yarn 集群提交我们的 Map Reduce 程序;
32 | 3. yarn 集群中的 Resourcemanger 和 nodemanager 进行通信,根据集群情况,分配 Container 给集群的某个 Nodemanager,Nodemanager 启动 Container;
33 | 4. Resource Manager 将 MapReduce Applicationmaster 分发到刚才 Nodemanager 启动的 container,然后自身在 container 中启动。
34 | 5. MapRedeuce ApplicationMaster 启动之后,立马向 Resource manager 注册,并为 MapReduce 申请资源。
35 | 6. MapReduce ApplicationMaster 申请到容器之后立马和 NodeManager 通信,将用户的 MapReduce 程序分发到对应的 Container 中运行,运行的是 Map 进行和 Reduce 进程。
36 | 7. Map 和 Reduce 进程执行期间与 MapReduce ApplicationMaster 进行通信,汇报自身的运行状态,如果运行结束,MapReduce ApplicationMaster ApplicationMaster 会向 ResourceManager 注销并释放所有的容器资源。
37 | 8. 最后返回 Reduce 的所有结果。
38 |
--------------------------------------------------------------------------------
/bigdata/hive.md:
--------------------------------------------------------------------------------
1 | # Hive
2 |
3 | ## 问题
4 | 1. Hive 数据倾斜的原因。
5 | - key 分布不均匀。
6 | - 业务数据本身的特性。
7 | - 建表考虑不周全。
8 | - 某些 HQL 语句本身就存在数据倾斜。
9 |
10 |
11 |
--------------------------------------------------------------------------------
/bigdata/hive_udf.md:
--------------------------------------------------------------------------------
1 | # Hive 函数
2 | 相信大家对 Hive 都不陌生,那么大家肯定用过 Hive 里面各种各样的函数。可能大家都会使用这些函数,但是没有自己动手去写过 Hive 里面的函数。下面主要来介绍一下 Hive 里面的各种函数。
3 |
4 |
5 | ## 依赖
6 | 开发 Hive UDF 之前,我们需要引入一个 jar,这个 jar 就是 hive-exec,里面定义了各种我们自定义的 UDF 函数的类型:UDF、GenericUDF、GenericUDTF 等。
7 |
8 | ```xml
9 |
10 |
11 | org.apache.hive
12 | hive-exec
13 | 2.1.1
14 |
15 |
16 | ```
17 |
18 |
19 | ## UDF(User-Defined-Function)
20 | UDF:用户自定义函数,也是实现起来最简单的一种函数。支持的就是**一进一出**类型的函数。
21 |
22 | 如何实现?
23 |
24 | - 继承 UDF 类。
25 |
26 | - 重写 evaluate 方法。
27 |
28 | - 将该 java 文件打包成 jar。
29 |
30 | - 在 beeline(hive 的一种终端)中输入如下命令:
31 |
32 | - 0: jdbc:hive2://localhost:10000> add jar /data/tommyyang/HiveUDF.jar;
33 |
34 | - 0: jdbc:hive2://localhost:10000> create temporary function ip2loc as 'cn.tommyyang.IPToLocation';
35 |
36 | - 0: jdbc:hive2://localhost:10000> select ip2loc("118.28.1.1");
37 |
38 | - 0: jdbc:hive2://localhost:10000> drop temporary function ip2loc;
39 |
40 | 具体代码实现:
41 |
42 | ```java
43 |
44 | @Description(
45 | name = "ip2loc",
46 | value = "_FUNC_(str) - covert ip to location",
47 | extended = "Example:\n" +
48 | " > SELECT ip2loc(ip) FROM ips;\n" +
49 | " [中国,上海]"
50 | )
51 | public class IPToLocation extends UDF {
52 |
53 | private static final InputStream stream = IPToLocation.class.getClassLoader().getResourceAsStream("ipipfree.ipdb");
54 | private static City db = null;
55 |
56 | static {
57 | try {
58 | db = new City(stream);
59 | } catch (IOException e) {
60 | e.printStackTrace();
61 | }
62 | }
63 |
64 | // 具体实现逻辑
65 | public ArrayList evaluate(Text s) throws IOException, IPFormatException {
66 | ArrayList allTexts = new ArrayList<>();
67 | if (s != null) {
68 | CityInfo info = db.findInfo(s.toString(), "CN");
69 | allTexts.add(info.getCountryName());
70 | allTexts.add(info.getRegionName());
71 | allTexts.add(info.getCityName());
72 | }
73 | return allTexts;
74 | }
75 |
76 | }
77 |
78 | ```
79 |
80 | @Description 为该 UDF 的描述,你可以通过命令 **desc function ip2loc**查看具体的描述;如下图:
81 |
82 |
83 | ## GenericUDF
84 | 相对 UDF,GenericUDF 就复杂一些,下面我们通过创建一个 containsString 方法的例子,
85 |
86 |
87 | ## GenericUDTF
88 |
--------------------------------------------------------------------------------
/bigdata/kafka_1.md:
--------------------------------------------------------------------------------
1 | ## kafka的几个重要概念
2 |
3 | - `Broker`:消息中间件处理节点,一个 Kafka 节点就是一个 broker,多个 broker 可以组成一个 Kafka 集群;
4 | - `Topic`:一类消息,例如 note impression 日志、 click 日志等都可以以 topic 的形式存在,Kafka 集群能够同时负责多个 topic 的分发;
5 | - `Partition`:topic 物理上的分组,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队;
6 | - `segment`:每个 partition 又由多个segment file组成;
7 | - `offset`:每个 partition 都由一系列有序的、不可变的消息组成,这些消息被连续的追加到 partition 中。partition 中的每个消息都有一个连续的序列号叫做 offset,用于 partition 唯一标识一条消息;
8 | - `message`:这个算是 kafka 文件中最小的存储单位,即是 one commit log。
9 |
10 | kafka 的 message 是以 topic 为基本单位,不同 topic 之间是相互独立的。
11 | 每个 topic 又可分为几个不同的 partition,每个 partition 存储一部分 message。
12 | 同一个 topic 的不同 partition 可以分布在不同的 broker 上,这正是分布式的设计。
13 | partition 是以文件夹的形式存储在 broker 机器上。
14 | topic 与 partition 的关系如下:
15 |
16 |
17 | ## Partition中的文件
18 | ### segment file
19 | 对于一个 partition,里面又有很多大小相等的 segment 数据文件(这个文件的具体大小可以在config/server.properties中进行设置),这种特性可以方便 old segment file的快速删除。
20 |
21 | 下面介绍一下 partition 中的 segment file的组成:
22 | 1. segment file 组成:由2部分组成,分别为 index file和 data file,这两个文件是一一对应的,后缀”.index”和”.log”分别表示索引文件和数据文件;数值最大为64位 long 大小,19位数字字符长度,没有数字用0填充;
23 | 2. 自0.10.0.1开始的kafka segment file组成:多了一部分,还有 .timeindex 索引文件,基于时间的索引文件;目前支持的时间戳类型有两种: CreateTime 和 LogAppendTime 前者表示 producer 创建这条消息的时间;后者表示 broker 接收到这条消息的时间(严格来说,是 leader broker 将这条消息写入到 log 的时间)
24 | 3. segment file 命名规则:partition 的第一个 segment 从0开始,后续每个 segment 文件名为上一个 segment 文件最后一条消息的 offset, ofsset 的数值最大为64位(long 类型),20位数字字符长度,没有数字用0填充。如下图所示:
25 | 老版本 segment file 结构:
26 |
27 | 新版本 segment file 结构:
28 |
29 |
30 | 4. 关于 segment file 中 index 索引文件与 data 文件对应关系图,这里我们借用网上的一个图片,如下所示:
31 |
32 |
33 | 5. segment的索引文件中存储着大量的元数据,数据文件中存储着大量消息,索引文件中的元数据指向对应数据文件中的 message 的物理偏移地址。以索引文件中的6,1407为例,在数据文件中表示第6个 message(在全局 partition 表示第368775个 message),以及该消息的物理偏移地址为1407。
34 |
35 | 6. Kafka message 结构如下图:
36 |
37 |
38 | `注`:.index文件的第一个数是 message 相对 offset,后面的数字是该消息的物理偏移地址。
39 |
40 |
41 | ### 为什么分成多个segment file
42 | 1. 问题: 如果 topic 的 partition 中只有一个文件会怎么样?
43 | - 新数据加在文件的末尾(调用内部方法),不论文件多大,该操作的时间复杂度都是O(1);这个没问题。
44 | - 查找某个 offset 的时候,是顺序查找。想想,如果文件很大的话,查找的效率就会很低;这个是要解决的。
45 |
46 | 2. Kakfa 是如何解决上述问题的呢
47 | 通过上述分析发现,如果 Kafka 只有一个文件的话,插入新数据的效率是没问题的;只是在查找的时候,效率很低。
48 |
49 | `解决办法`
50 |
51 | `方法一` 数据文件分段
52 |
53 | 将大文件分成多个小的文件,便于维护。 由 offset 的起始位置来命名,则通过二分查找可以确定一个待查找的 offset
54 | 属于在那个小文件里面。
55 |
56 | `方法二` 为数据文件建立索引文件
57 |
58 | 即为上图中可以看到的 .index 文件, 数据分段虽然解决了一个大文件的问题,但是找到具体的小文件后,还是要通过
59 | 顺序扫描的方式才能找到对应 offset 的 message。 为了提高顺序扫描的效率,kafka 为每个分段后的文件建立了一个
60 | 与数据文件名一样的,扩展名为 .index 的文件。
61 |
62 | **索引文件的内部结构**
63 |
64 | 索引文件包含两个部分(均为4个字节),分别为 offset 和 position。
65 |
66 | - 相对 offset: 由于数据文件分段以后,除了第一个数据以外,每个数据文件的起始 offset 不为0,相对 offset 表示
67 | 该 message 相对于其所属数据文件中最小的 offset 的大小,即在每个文件中都是从1开始。 然后查找具体 offset 的时候,
68 | 只需要通过二分查找找到具体的在哪个文件中,然后再用 offset - 文件名对应的数值, 即可确定在文件中的相对 offset。
69 | 存储相对 offset 的好处是*可以减小索引文件占用的空间*。
70 |
71 | - position: 表示该条 message 在数据文件中的绝对位置, 只要打开数据文件并移动文件指针到这个 position 就可以
72 | 读取到对应的 message 数据了。
73 |
74 | 3. 通过 offset 查找 message
75 | 分为两个步骤:
76 |
77 | - 通过`二分查找`文件列表,快速定位到具体的.index和.log文件; 即找到小于或等于给定 offset 的最大的 offset 文件。
78 |
79 | - 通过 segment file 查找具体的 message,找到具体的文件后,先定位到 .index 文件中的 元数据物理位置 position,
80 | 即 .log 文件中的物理偏移地址。 然后在通过顺序查找到具体的 offset。
81 |
82 | 上述最后还需要顺序查找具体的 offset, 而不是直接通过 position 定位到具体的 message,是因为 segment index file
83 | 没有为数据文件中的每条 message 建立索引,而是采用`稀疏索引`的存储方式,每隔一定字节的数据建立一条索引,这样可以减小
84 | 索引文件,通过 map 可以直接进行内存操作, 稀疏索引为数据文件的每个对应 message 设置一个元数据指针, 这样比稠密索引
85 | 节省了存储空间,但是查找时需要消耗更多的时间,其实最后通过 .index 文件中 position 无法直接定位到 没有建立索引
86 | 的 message, 而是需要通过顺序查找,再继续在 .log 文件中继续往下查找。
87 |
88 | ### 总结
89 |
90 | Kafka 高效文件存储设计特点:
91 |
92 | - 将 topic 中一个 partition 大文件分割成多个小文件段,这样更容易定期清除和删除已经消费完的文件,减少磁盘占用。
93 | - 通过索引可以快速定位到 message 和 确定 response 的最大大小。
94 | - 通过 index 元数据全部映射到 memory,可以避免 segment file的 IO 磁盘操作。
95 | - 通过索引文件稀疏存储,可以大幅降低 index 文件元数据占用空间大小。
96 |
97 |
98 | ### 参考
99 |
100 | - [kafka-fs-design-theory](https://tech.meituan.com/2015/01/13/kafka-fs-design-theory.html)
101 | - [Kafka 存储](http://matt33.com/2016/03/08/kafka-store/)
102 |
103 |
104 |
--------------------------------------------------------------------------------
/bigdata/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | javainterview
7 | cn.tommyyang
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | bigdata
13 |
14 |
15 |
16 |
17 | org.apache.hive
18 | hive-exec
19 | 3.1.1
20 |
21 |
22 | org.apache.zookeeper
23 | zookeeper
24 |
25 |
26 | org.apache.hadoop
27 | hadoop-hdfs
28 |
29 |
30 | org.apache.httpcomponents
31 | httpcore
32 |
33 |
34 | org.apache.httpcomponents
35 | httpclient
36 |
37 |
38 | org.apache.logging.log4j
39 | log4j-1.2-api
40 |
41 |
42 | org.apache.logging.log4j
43 | log4j-slf4j-impl
44 |
45 |
46 | org.slf4j
47 | slf4j-api
48 |
49 |
50 |
51 |
52 |
53 | net.ipip
54 | ipdb
55 | 1.1.2
56 |
57 |
58 |
59 |
60 |
61 |
62 | org.apache.maven.plugins
63 | maven-compiler-plugin
64 |
65 | 1.8
66 | 1.8
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/bigdata/src/main/java/cn/tommyyang/bigfile/BigFile.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.bigfile;
2 |
3 | import cn.tommyyang.bigfile.fileservice.FileService;
4 |
5 | import java.io.IOException;
6 |
7 | /**
8 | * @author TommyYang on 2019-04-09
9 | *
10 | * 使用说明
11 | * run cmd: java -cp bigdata-1.0-SNAPSHOT.jar cn.tommyyang.bigfile.BigFile
12 | */
13 | public class BigFile {
14 |
15 | public static void main(String[] args) throws IOException {
16 | //BigFileTool.readContent(args[0], args[1]);
17 | FileService fileService = new FileService("./smallfiles/sink-0.txt");
18 | fileService.countWords();
19 | System.out.println(fileService.getTreeMap());
20 | System.out.println(fileService.getTreeMap().firstEntry().getKey() + ":" + fileService.getTreeMap().firstEntry().getValue());
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/bigdata/src/main/java/cn/tommyyang/bigfile/fileservice/FileService.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.bigfile.fileservice;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.IOException;
6 | import java.nio.ByteBuffer;
7 | import java.nio.channels.FileChannel;
8 | import java.util.TreeMap;
9 |
10 | /**
11 | * @author TommyYang on 2019-04-12
12 | */
13 | public class FileService {
14 |
15 | private String fileName;
16 |
17 | private TreeMap treeMap;
18 |
19 | public FileService(String fileName) {
20 | this.fileName = fileName;
21 | this.treeMap = new TreeMap<>();
22 | }
23 |
24 | public TreeMap getTreeMap() {
25 | return treeMap;
26 | }
27 |
28 | public void countWords() throws IOException {
29 | File file = new File(this.fileName);
30 | FileInputStream inputStream = new FileInputStream(file);
31 | FileChannel fc = inputStream.getChannel();
32 |
33 | ByteBuffer bf = ByteBuffer.allocate(10 * 1024 * 1024);
34 |
35 | int len = -1;
36 | while ((len = fc.read(bf)) != -1){
37 | bf.clear();
38 | byte[] bytes = bf.array();
39 | String values = new String(bytes, 0 , len);
40 | String[] valArr = values.split(System.lineSeparator());
41 | for (String val : valArr){
42 | Long cnt = this.treeMap.get(val);
43 | if (cnt == null){
44 | this.treeMap.put(val, 0l);
45 | }else {
46 | this.treeMap.put(val, ++cnt);
47 | }
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/bigdata/src/main/java/cn/tommyyang/bigfile/utils/BigFileTool.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.bigfile.utils;
2 |
3 | import java.io.*;
4 | import java.nio.ByteBuffer;
5 | import java.nio.channels.FileChannel;
6 | import java.nio.charset.Charset;
7 |
8 | /**
9 | * @author TommyYang on 2019-04-09
10 | */
11 | public class BigFileTool {
12 |
13 | public static void readContent(String filePath, String sinkDir) throws IOException {
14 | File file = new File(filePath);
15 | FileInputStream inputStream = new FileInputStream(file);
16 | FileChannel channel = inputStream.getChannel();
17 |
18 | ByteBuffer buffer = ByteBuffer.allocate(8092);
19 | int length = -1;
20 | while ((length = channel.read(buffer)) != -1){
21 | buffer.clear();
22 |
23 | byte[] bytes = buffer.array();
24 | String values = new String(bytes, 0 , length);
25 |
26 | String[] valArr = values.split(" ");
27 | for (String val : valArr){
28 | int code = Math.abs(val.hashCode()) & 15;
29 | String txtName = "sink-" + code + ".txt";
30 | String sinkPath = sinkDir + txtName;
31 | writeContent(sinkPath, Charset.forName("utf-8").encode(val + System.lineSeparator()));
32 | }
33 | }
34 | }
35 |
36 | public static void writeContent(String sinkPath, ByteBuffer bf) throws IOException {
37 | FileOutputStream outputStream = new FileOutputStream(new File(sinkPath), true);
38 | FileChannel channel = outputStream.getChannel();
39 | channel.write(bf);
40 | channel.close();
41 | outputStream.close();
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/bigdata/src/main/java/cn/tommyyang/bigfile/utils/IHandle.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.bigfile.utils;
2 |
3 | /**
4 | * @author TommyYang on 2019-04-12
5 | */
6 | public interface IHandle {
7 |
8 | void handle(String line);
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/bigdata/src/main/java/cn/tommyyang/collections/ListUtils.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.collections;
2 |
3 | import java.util.*;
4 |
5 | /**
6 | * @Author : TommyYang
7 | * @Time : 2019-05-31 16:07
8 | * @Software: IntelliJ IDEA
9 | * @File : ListUtils.java
10 | */
11 | public class ListUtils {
12 |
13 | public static List maxArrayList(int size) {
14 | List strList = new ArrayList(size);
15 | for (int i = 0; i < size; i++) {
16 | strList.add(i + "test");
17 | }
18 | return strList;
19 | }
20 |
21 | public static List maxList(int size) {
22 | List strList = new LinkedList();
23 | for (int i = 0; i < size; i++) {
24 | strList.add(i + "test");
25 | }
26 | return strList;
27 | }
28 |
29 | public static List testList(int size) {
30 | List testList = new ArrayList();
31 | for (int i = 0; i < size; i++) {
32 | testList.add(i + "test");
33 | }
34 | return testList;
35 | }
36 |
37 | public static Set testSet(int size) {
38 | Set testSet = new HashSet();
39 | for (int i = 0; i < size; i++) {
40 | testSet.add(i + "test");
41 | }
42 | return testSet;
43 | }
44 |
45 | public static void deWeightList(List des, List sourse) {
46 | if (sourse == null || sourse.size() <= 0) {
47 | return;
48 | }
49 | Iterator listStr = sourse.iterator();
50 | while (listStr.hasNext()) {
51 | String item = listStr.next();
52 | if (des.contains(item)) {
53 | listStr.remove(); //考虑到list的删除效率慢,此种方法对于大数据集合来说不合适
54 | }
55 | }
56 | System.out.println("after deWight list size: " + sourse.size());
57 | }
58 |
59 | public static void deWeightList(Set des, List sourse) {
60 | if (sourse == null || sourse.size() <= 0) {
61 | return;
62 | }
63 | Iterator listStr = sourse.iterator();
64 | while (listStr.hasNext()) {
65 | String item = listStr.next();
66 | if (des.contains(item)) {
67 | listStr.remove(); //考虑到list的删除效率慢,此种方法对于大数据集合来说不合适
68 | }
69 | }
70 | System.out.println("after deWight list size: " + sourse.size());
71 | }
72 |
73 | public static void deWeightListByNewList(Set des, List sourse) {
74 | if (sourse == null || sourse.size() <= 0) {
75 | return;
76 | }
77 | Iterator listStr = sourse.iterator();
78 | List existList = new ArrayList();
79 | while (listStr.hasNext()) {
80 | String item = listStr.next();
81 | if(!des.contains(item)){
82 | //TODO 对去重后的数据进行逻辑操作,不一定要删除,可以换个思路(是否可以直接逻辑操作,不一定非要再把数据写进集合后,然后遍历集合在进行逻辑操作)
83 | existList.add(item); //改成添加进新的list,考虑到list的删除效率慢(非要得到删除后的集合的情况下,否则走else)
84 | }
85 | }
86 | sourse.clear();
87 | sourse = existList;
88 | System.out.println("after deWight list size: " + sourse.size());
89 | }
90 |
91 | public static void deWeightListOther(List des, List sourse) {
92 | if (sourse == null || sourse.size() <= 0) {
93 | return;
94 | }
95 | for (int i = sourse.size() - 1; i >= 0; i--) {
96 | String str = sourse.get(i);
97 | for (String item : des) {
98 | if (str.equals(item)) {
99 | sourse.remove(i);
100 | break;
101 | }
102 | }
103 | }
104 | System.out.println("after other deWight list size: " + sourse.size());
105 | }
106 |
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/bigdata/src/main/java/cn/tommyyang/collections/RunTest.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.collections;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 | import java.util.List;
6 | import java.util.Set;
7 |
8 | /**
9 | * @Author : TommyYang
10 | * @Time : 2019-05-31 16:09
11 | * @Software: IntelliJ IDEA
12 | * @File : RunTest.java
13 | */
14 | public class RunTest {
15 |
16 | public static void main(String[] args) {
17 | SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
18 |
19 | List maxArrayList = ListUtils.maxArrayList(25000000);
20 | // Set maxSet = new HashSet(maxArrayList);
21 | // maxSet.addAll(maxArrayList);
22 |
23 | List testList = ListUtils.testList(20000);
24 | Set testSet = ListUtils.testSet(1500000);
25 |
26 | //遍历过程中去重
27 | System.out.println("start test foreach list directly, start time: " + sdf.format(new Date()));
28 |
29 | for (String item: maxArrayList) {
30 | if(!testSet.contains(item)){
31 | //TODO
32 | }
33 | }
34 |
35 | System.out.println("end test foreach list directly, end time: " + sdf.format(new Date()) + "\n");
36 |
37 |
38 | //List结合List去重
39 | System.out.println("start test list, start time: " + sdf.format(new Date()));
40 |
41 | ListUtils.deWeightList(testList, maxArrayList);
42 |
43 | System.out.println("end test list, end time: " + sdf.format(new Date()) + "\n");
44 |
45 | maxArrayList.clear();
46 | maxArrayList = ListUtils.maxArrayList(25000000);
47 |
48 | //List结合Set去重
49 | System.out.println("start test set, start time: " + sdf.format(new Date()));
50 |
51 | ListUtils.deWeightList(testSet, maxArrayList);
52 |
53 | System.out.println("end test set, end time: " + sdf.format(new Date()));
54 |
55 | maxArrayList.clear();
56 | maxArrayList = ListUtils.maxArrayList(25000000);
57 | //List结合Set去重(不是直接对list进行删除,而是组装新list,考虑到list删除效率低)
58 | System.out.println("start test set, start time: " + sdf.format(new Date()));
59 |
60 | ListUtils.deWeightListByNewList(testSet, maxArrayList);
61 |
62 | System.out.println("end test set, end time: " + sdf.format(new Date()));
63 |
64 |
65 | }
66 |
67 |
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/bigdata/src/main/java/cn/tommyyang/hive/udf/ContainsString.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.hive.udf;
2 |
3 | import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
4 | import org.apache.hadoop.hive.ql.metadata.HiveException;
5 | import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
6 | import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
7 |
8 | /**
9 | * @Author : TommyYang
10 | * @Time : 2019-09-19 15:22
11 | * @Software: IntelliJ IDEA
12 | * @File : ContainsString.java
13 | */
14 | public class ContainsString extends GenericUDF {
15 |
16 | @Override
17 | public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {
18 | return null;
19 | }
20 |
21 | @Override
22 | public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
23 | return null;
24 | }
25 |
26 | @Override
27 | public String getDisplayString(String[] strings) {
28 | return null;
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/bigdata/src/main/java/cn/tommyyang/hive/udf/IPToLocation.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.hive.udf;
2 |
3 | import net.ipip.ipdb.City;
4 | import net.ipip.ipdb.CityInfo;
5 | import net.ipip.ipdb.IPFormatException;
6 | import org.apache.hadoop.hive.ql.exec.Description;
7 | import org.apache.hadoop.hive.ql.exec.UDF;
8 | import org.apache.hadoop.io.Text;
9 |
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 | import java.util.ArrayList;
13 |
14 | /**
15 | * @Author : TommyYang
16 | * @Time : 2019-08-30 16:53
17 | * @Software: IntelliJ IDEA
18 | * @File : IPToLocation.java
19 | */
20 | @Description(
21 | name = "ip2loc",
22 | value = "_FUNC_(str) - covert ip to location",
23 | extended = "Example:\n" +
24 | " > SELECT ip2loc(ip) FROM ips;\n" +
25 | " [中国,上海]"
26 | )
27 | public class IPToLocation extends UDF {
28 |
29 | private static final InputStream stream = IPToLocation.class.getClassLoader().getResourceAsStream("ipipfree.ipdb");
30 | private static City db = null;
31 |
32 | static {
33 | try {
34 | db = new City(stream);
35 | } catch (IOException e) {
36 | e.printStackTrace();
37 | }
38 | }
39 |
40 | // 具体实现逻辑
41 | public ArrayList evaluate(Text s) throws IOException, IPFormatException {
42 | ArrayList allTexts = new ArrayList<>();
43 | if (s != null) {
44 | CityInfo info = db.findInfo(s.toString(), "CN");
45 | allTexts.add(info.getCountryName());
46 | allTexts.add(info.getRegionName());
47 | allTexts.add(info.getCityName());
48 | }
49 | return allTexts;
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/books/README.md:
--------------------------------------------------------------------------------
1 | # 书籍总结
2 | 本文主要分享个人总结的电子书,如有侵权,请通知删除,谢谢!
3 |
4 | ## 大数据
5 | | 书名 | 链接 | 提取码 |
6 | | :----: | :----: | :----: |
7 | | Kafka技术内幕.pdf | [下载](https://pan.baidu.com/s/1ue-o_Q4mnVK8aXYc044Vyw) | 4osu |
8 | | Kafka权威指南.pdf | [下载](https://pan.baidu.com/s/1gdLZ28_BfH-cg8HFRupbmA) | d05a |
9 | | Redis 设计与实现.pdf | [下载](https://pan.baidu.com/s/1ySc4g8CCBcm8ec6EqLnaEQ) | osbz |
10 | | Redis 深度历险:核心原理和应用实践.pdf | [下载](https://pan.baidu.com/s/1hC_JUeBhCXFjYPNZ8b3xuw) | qdcg |
11 | | Redis 开发与运维.pdf | [下载](https://pan.baidu.com/s/1u1GwsqPerdf7N9y0j3yKOg) | uwy9 |
12 |
13 | ## Java
14 | | 书名 | 链接 | 提取码 |
15 | | :----: | :----: | :----: |
16 | | Effective Java 中文版(第 2 版).pdf | [下载](https://pan.baidu.com/s/150ztSubX3-NhgMHMPiRFYQ) | mmdw |
17 | | 实战 Java 高并发程序设计.pdf | [下载](https://pan.baidu.com/s/1QUse0rmMBIvxFgeiJZ7TxQ) | l9xt |
18 | | Java8 实战.pdf | [下载](https://pan.baidu.com/s/1y5m1hgn9cJT7pyE5qI9UuQ) | og1w |
19 | | 深入理解 Java 虚拟机第二版.pdf | [下载](https://pan.baidu.com/s/1mFE-B03b5Dwuz3_CJgHA7g) | c1j1 |
20 |
21 | ## 算法
22 | | 书名 | 链接 | 提取码 |
23 | | :----: | :----: | :----: |
24 | | 编程珠玑(第 2 版).pdf | [下载](https://pan.baidu.com/s/174v9WNIHBFpAxmy9uCYX-g) | 5698 |
25 |
26 | ## 架构
27 | | 书名 | 链接 | 提取码 |
28 | | :----: | :----: | :----: |
29 | | 微服务设计.pdf | [下载](https://pan.baidu.com/s/1uaCQhagPU1ElrC2zuBePdA) | bfir |
30 | | 大型网站技术架构.pdf | [下载](https://pan.baidu.com/s/1F_CpOz-0sspDjGktG1z3Yw) | wf1l |
31 |
32 | ## 人工智能
33 | ### 读书笔记
34 | #### A/B测试
35 | 
--------------------------------------------------------------------------------
/codeinterview/README.md:
--------------------------------------------------------------------------------
1 | # 代码篇
2 | ## LeetCode
3 |
4 |
5 | ## 面试中遇到的具体编码问题
6 | - [多线程(使用线程池)按顺序打印 0-100;(至少3个线程交替按顺序打印)](order-print-num.md)
7 | - [爬楼梯问题](dynamic-programming.md#L11)
8 |
9 | ## 算法相关
10 | - [动态规划](dynamic-programming.md)
--------------------------------------------------------------------------------
/codeinterview/dynamic-programming.md:
--------------------------------------------------------------------------------
1 | # 动态规划(Dynamic Programming)
2 | 动态规划其实和分治策略是类似的,也是将一个原问题分解为若干个规模较小的子问题,递归的求解这些子问题,然后合并子问题的解得到原问题的解。
3 | 区别在于这些子问题会有重叠,一个子问题在求解后,可能会再次求解,于是我们想到将这些子问题的**解存储起来**,当下次再次求解这个子问题时,直接拿过来就是。
4 | 其实就是说,动态规划所解决的问题是分治策略所解决问题的一个子集,只是这个子集更适合用动态规划来解决从而得到更小的运行时间。
5 | **即用动态规划能解决的问题分治策略肯定能解决,只是运行时间长了**。因此,分治策略一般用来解决子问题相互对立的问题,称为标准分治,而动态规划用来解决子问题重叠的问题。
6 |
7 | 将 **动态规划** 的概念关键点抽离出来描述就是这样的:
8 | - 动态规划法试图只解决每个子问题一次。
9 | - 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。
10 |
11 | ## 爬楼梯问题
12 | 下面通过爬楼梯问题来分析使用动态规划的解决问题(该问题也是在现场面试中遇到的)。
13 |
14 | **问题描述**:爬楼梯,我们每次可以走 1 级阶梯或者 2 级阶梯,那我们走 50(n) 级阶梯总共有多少种走法。
15 | 在现场思考过程中,如果没有使用动态规划的话,那就要用递归的概念去做。
16 |
17 | ### 递归方式
18 | 我们在高中的数学课里面应该学习过规律推理,那我们可以很容易的去推理出来公式:
19 | 1 级台阶: 1 种走法(f(1))
20 | 2 级台阶: 2 种走法(f(2))
21 | 3 级台阶: 3 种走法(f(3) = f(2) + f(1))
22 | 4 级台阶: 5 种走法(f(4) = f(3) + f(2))
23 | 5 级台阶: 8 种走法(f(5) = f(4) + f(3))
24 | ...
25 | n 级台阶: f(n) = f(n-1) + f(n-2) **(n > 2)**
26 |
27 | 通过以上公式,很容易推导出一下递归代码:
28 |
29 | ``` java
30 |
31 | int f(int n) {
32 | if (n == 1) return 1;
33 | if (n == 2) return 2;
34 | return f(n-1) + f(n-2);
35 | }
36 |
37 | ```
38 |
39 | code:
40 |
41 | ``` java
42 |
43 | int f(int n) {
44 | if (n == 1) return 1;
45 | if (n == 2) return 2;
46 | // a 保存倒数第二个子状态数据,b 保存倒数第一个子状态数据, temp 保存当前状态的数据
47 | int a = 1, b = 2;
48 | int temp = a + b;
49 | for (int i = 3; i <= n; i++) {
50 | temp = a + b;
51 | a = b;
52 | b = temp;
53 | }
54 | return temp;
55 | }
56 |
57 | ```
58 |
59 | ### 从递归到动态规划
60 | 还是以**爬台阶**为例,如果以递归的方式解决的话,那么这种方法的时间复杂度为O(2^n)
61 |
62 | ### 详解动态规划
63 |
64 | **动态规划**中包含三个重要的概念:
65 | - 最优子结构
66 | - 边界
67 | - 状态转移公式
68 |
69 | 在**爬台阶问题**中:
70 |
71 | f(10) = f(9) + f(8) 是最优子结构
72 | f(1) 与 f(2) 是边界
73 | f(n) = f(n-1) + f(n-2) 状态转移公式
74 |
75 | **爬台阶问题**只是动态规划中相对简单的问题,因为它只有一个变化维度,如果涉及多个维度的话,那么问题就变得复杂多了。
76 |
77 | 难点就在于找出**动态规划**中的这三个概念。感觉跟我们高中学习的推理证明题有点像,通过现在的条件推断出结果。
78 |
79 | ## 国王和金矿问题
80 | ### 问题描述
81 | 有一个国家发现了 5 座金矿,每座金矿的黄金储量不同,需要参与挖掘的工人数也不同。参与挖矿工人的总数是 10 人。每座金矿要么全挖,要么不挖,不能派出一半人挖取一半金矿。要求用程序求解出,要想得到尽可能多的黄金,应该选择挖取哪几座金矿?
--------------------------------------------------------------------------------
/codeinterview/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | javainterview
7 | cn.tommyyang
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | codeinterview
13 |
14 |
15 |
16 |
17 | org.apache.maven.plugins
18 | maven-compiler-plugin
19 |
20 | 1.8
21 | 1.8
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/array/FindPosition.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.array;
2 |
3 | /**
4 | * @author TommyYang on 2019-03-27
5 | */
6 | public class FindPosition {
7 |
8 | public int searchInsert(int[] nums, int target) {
9 | if (nums == null || nums.length == 0 || nums[0] >= target){
10 | return 0;
11 | }
12 | for (int i = 0; i < nums.length; i++){
13 | if (nums[i] >= target){
14 | return i;
15 | }
16 | }
17 |
18 | return nums.length;
19 |
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/array/InterSection.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.array;
2 |
3 |
4 | import java.util.HashSet;
5 | import java.util.Set;
6 |
7 | /**
8 | * @author TommyYang on 2019-05-19
9 | */
10 | //求两个数组的交集(https://leetcode-cn.com/problems/intersection-of-two-arrays/)
11 | public class InterSection {
12 |
13 | //暂时没想到更好的解法,感觉解法效率有待提高。
14 | public int[] intersection(int[] nums1, int[] nums2) {
15 |
16 | if(nums1 == null || nums2 == null){
17 | return new int[]{};
18 | }
19 |
20 | Set set = new HashSet(nums1.length);
21 | for (int i : nums1){
22 | set.add(i);
23 | }
24 |
25 | Set res = new HashSet(nums2.length);
26 | for (int i : nums2){
27 | if (set.contains(i)){
28 | res.add(i);
29 | }
30 | }
31 |
32 | int[] resArr = new int[res.size()];
33 |
34 | int index = 0;
35 | for(int i : res){
36 | resArr[index++] = i;
37 | }
38 |
39 | return resArr;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/array/TwoSortArrMerge.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.array;
2 |
3 | /**
4 | * @author TommyYang on 2019-03-21
5 | */
6 | public class TwoSortArrMerge {
7 |
8 | public static void main(String[] args) {
9 | int[] nums1 = new int[]{2,5,6, 0 , 0, 0};
10 | int[] nums2 = new int[]{1,2,3};
11 |
12 | merge(nums1, 3, nums2, 3);
13 |
14 | for(int i : nums1){
15 | System.out.println(i);
16 | }
17 | }
18 |
19 | public static void merge(int[] nums1, int m, int[] nums2, int n) {
20 | int i = m - 1, j = n - 1, index = m + n - 1;
21 | while (i >= 0 || j >= 0){
22 | //i < 0; 说明 nums1已经填充完了,只剩下nums2,所以只需要把nums2填充到nums1对应的index上就行
23 | if(i < 0){
24 | nums1[index--] = nums2[j--];
25 | continue;
26 | }else if (j < 0){
27 | // j < 0; 说明nums2已经全部填充到了nums1,直接跳出循环就行了;
28 | break;
29 | }
30 | //将数据填充到具体的index
31 | if(nums1[i] >= nums2[j]){
32 | nums1[index--] = nums1[i--];
33 | } else {
34 | nums1[index--] = nums2[j--];
35 | }
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/CrossLinkedList.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * @author TommyYang on 2019-03-25
5 | */
6 |
7 | //相交链表题目(https://leetcode-cn.com/problems/intersection-of-two-linked-lists/)
8 | public class CrossLinkedList {
9 |
10 | //找到两个单链表相交的起始节点,返回相交的链表
11 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
12 |
13 | ListNode first = headA;
14 | ListNode second = headB;
15 |
16 | //当第一个链表运行完后,赋值给第二个链表的头节点;
17 | //第二个链表运行完后,赋值给第一个链表的头结点;
18 | //运行到相交的时候(相交),或者都运行到null的时候(不相交),都是走了同样的距离;可以画图结合理解更简单。
19 | while (first != second){
20 | first = (first == null ? headB : first.next);
21 | second = (second == null ? headA : second.next);
22 | }
23 |
24 | return first;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/CycleNode2.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * @author TommyYang on 2019-05-06
5 | */
6 | //环形链表2(https://leetcode-cn.com/problems/linked-list-cycle-ii/)
7 | public class CycleNode2 {
8 |
9 | public ListNode detectCycle(ListNode head) {
10 | ListNode fast = head;
11 | ListNode slow = head;
12 | boolean meet = false;
13 |
14 | while (fast != null && fast.next != null){
15 | fast = meet ? fast.next : fast.next.next;
16 | slow = slow.next;
17 |
18 | if (fast == slow){
19 | if (!meet){
20 | //说明环相交的地方在头结点,则直接相交的时候,快的结点走了两圈,慢的结点走了一圈
21 | if (fast == head){
22 | return fast;
23 | }
24 | // 如果相交的地方不在头节点,通过a+b+b+c=2(a+b);
25 | // 这题一定要利用fast指针的速度是slow指针的2倍,得到fast指针重设为head指针
26 | // 运行后第二次相遇的地方一定是相交的地方
27 | fast = head;
28 | meet = true;
29 | } else {
30 | return fast;
31 | }
32 | }
33 | }
34 |
35 | return null;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/DeleteNodeInLinkedList.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * @author TommyYang on 2019-05-07
5 | */
6 | //删除某个链表中给定的(非末尾)节点
7 | public class DeleteNodeInLinkedList {
8 |
9 | //其实这个题目很简单 删除某个结点 其实你可以想成是删除某个结点的后面一个结点
10 | //同时把后面一个结点的数据填充到当前结点 从而做到删除当前结点
11 | public void deleteNode(ListNode node) {
12 | node.val = node.next.val;
13 | node.next = node.next.next;
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/DetectCycle.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * @author TommyYang on 2019-04-08
5 | */
6 | public class DetectCycle {
7 |
8 | public ListNode detectCycle(ListNode head){
9 | return null;
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/HasCycle.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * @author TommyYang on 2019-04-08
5 | */
6 | public class HasCycle {
7 |
8 | public boolean hasCycle(ListNode head){
9 | ListNode dummy = new ListNode(0);
10 |
11 | ListNode first = dummy, second = dummy;
12 |
13 | while (second != null && second.next != null){
14 | first = first.next;
15 | second = second.next.next;
16 |
17 | if (first == second){
18 | return true;
19 | }
20 | }
21 |
22 | return false;
23 |
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/ListNode.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * @author TommyYang on 2019-03-20
5 | */
6 | public class ListNode {
7 |
8 | int val;
9 |
10 | ListNode next;
11 |
12 | public ListNode(int val) {
13 | this.val = val;
14 | }
15 |
16 | public ListNode(int val, ListNode next) {
17 | this.val = val;
18 | this.next = next;
19 | }
20 |
21 | public ListNode getNext() {
22 | return next;
23 | }
24 |
25 | public void setNext(ListNode next) {
26 | this.next = next;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/MergeTwoSortLinkedList.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * @author TommyYang on 2019-03-20
5 | */
6 | public class MergeTwoSortLinkedList {
7 |
8 | public static void main(String[] args) throws InterruptedException {
9 | ListNode node1 = new ListNode(1);
10 | ListNode node2 = new ListNode(3);
11 | ListNode node3 = new ListNode(4);
12 |
13 | ListNode node4 = new ListNode(1);
14 | ListNode node5 = new ListNode(2);
15 | ListNode node6 = new ListNode(4);
16 |
17 | node1.setNext(node2);
18 | node2.setNext(node3);
19 |
20 | node4.setNext(node5);
21 | node5.setNext(node6);
22 |
23 | ListNode head = mergeTwoLists(node1, node4);
24 | while (head != null){
25 | System.out.println(head.val);
26 | head = head.next;
27 | }
28 | }
29 |
30 | public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
31 | // if(l1 == null){
32 | // return l2;
33 | // }
34 | //
35 | // if(l2 == null){
36 | // return l1;
37 | // }
38 | //
39 | // ListNode tmp;
40 | // if(l1.val > l2.val){
41 | // tmp = l1;
42 | // l2 = tmp;
43 | // l1 = l2;
44 | // }
45 | // ListNode head = l1;
46 | // ListNode tmp2;
47 | // while(l1.next != null && l2 != null){
48 | // if(l1.val <= l2.val && l1.next.val <= l2.val){
49 | // l1 = l1.next;
50 | // }else if (l1.val <= l2.val && l1.next.val > l2.val){
51 | // tmp = l1.next;
52 | // l1.next = l2;
53 | // tmp2 = l2.next;
54 | // l2.next = tmp;
55 | // l2 = tmp2;
56 | // l1 = l1.next;
57 | // }
58 | // }
59 | // if(l1 != null){
60 | // l1.next = l2;
61 | // }
62 | //
63 | // return head;
64 |
65 | if(l1 == null){
66 | return l2;
67 | }
68 |
69 | if(l2 == null){
70 | return l1;
71 | }
72 |
73 | if(l1.val <= l2.val){
74 | l1.next = mergeTwoLists(l1.next, l2);
75 | return l1;
76 | } else{
77 | l2.next = mergeTwoLists(l1, l2.next);
78 | return l2;
79 | }
80 |
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/RemoveElementsInLinkedList.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * @author TommyYang on 2019-05-07
5 | */
6 | //删除链表中等于给定值 val 的所有节点。
7 | public class RemoveElementsInLinkedList {
8 |
9 | public ListNode removeElements(ListNode head, int val) {
10 | ListNode dummy = new ListNode(-1);
11 | dummy.next = head;
12 |
13 | ListNode current = dummy;
14 | while (current.next != null){
15 | if (current.next.val == val) {
16 | // 删除链表后面一个结点后 即相当于链表后移了一个位置
17 | // 需要继续判断current.next.val 需不需要移除
18 | current.next = current.next.next;
19 | }else {
20 | current = current.next;
21 | }
22 |
23 | }
24 | return dummy.next;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/RemoveNthFromEnd.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * @author TommyYang on 2019-04-08
5 | */
6 | public class RemoveNthFromEnd {
7 |
8 | public ListNode removeNthFromEnd(ListNode head, int n){
9 | ListNode dummy = new ListNode(0);
10 | dummy.next = head;
11 |
12 | ListNode first = dummy, second = dummy;
13 |
14 | for(int i = 0; i <= n; i++){
15 | first = first.next;
16 | }
17 |
18 | while (first != null){
19 | first = first.next;
20 | second = second.next;
21 | }
22 |
23 | second.next = second.next.next;
24 |
25 | return dummy.next;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/ReverseLinkedList.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * 链表反转
5 | * 1、迭代算法
6 | * 2、递归算法
7 | *
8 | * @Author : TommyYang
9 | * @Time : 2019-06-19 18:29
10 | * @Software: IntelliJ IDEA
11 | * @File : ReverseLinkedList.java
12 | */
13 | public class ReverseLinkedList {
14 |
15 | /**
16 | * 迭代算法反转
17 | *
18 | * @param head
19 | * @return
20 | */
21 | public ListNode reverseWithIterate(ListNode head) {
22 | ListNode cur = head;
23 | ListNode next;
24 | ListNode pre = null;
25 |
26 | while (cur != null) {
27 | next = cur.next;
28 | cur.next = pre;
29 | pre = cur;
30 | cur = next;
31 | }
32 | return pre;
33 | }
34 |
35 | /**
36 | * 递归算法反转
37 | *
38 | * @param head
39 | * @return
40 | */
41 | public ListNode reverseWithRecursion(ListNode head) {
42 | if (head == null || head.next == null) {
43 | return head;
44 | }
45 |
46 | ListNode newNode = reverseWithRecursion(head.next);
47 |
48 | head.next.next = head;
49 | head.next = null;
50 |
51 | return newNode;
52 | }
53 |
54 | public static void main(String[] args) {
55 | ListNode node5 = new ListNode(5, null);
56 | ListNode node4 = new ListNode(4, node5);
57 | ListNode node3 = new ListNode(3, node4);
58 | ListNode node2 = new ListNode(2, node3);
59 | ListNode node1 = new ListNode(1, node2);
60 |
61 | print(node1);
62 |
63 | ListNode newNode = new ReverseLinkedList().reverseWithRecursion(node1);
64 |
65 | print(newNode);
66 | }
67 |
68 | /**
69 | * 打印链表
70 | *
71 | * @param head 链表头
72 | */
73 | private static void print(ListNode head) {
74 | while (head != null) {
75 | System.out.print(head.val);
76 | if (head.next != null) {
77 | System.out.print("->");
78 | }
79 | head = head.next;
80 | }
81 | System.out.println();
82 | }
83 |
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/listnode/ReverseLinkedList2.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.listnode;
2 |
3 | /**
4 | * @author TommyYang on 2019-05-04
5 | */
6 | //反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
7 | public class ReverseLinkedList2 {
8 |
9 | public ListNode reverseBetween(ListNode head, int m, int n) {
10 |
11 | ListNode dummy = new ListNode(0);
12 | dummy.next = head;
13 |
14 | ListNode index = dummy;
15 | ListNode left, right, tmp;
16 |
17 | //count 为倒转链表的长度
18 | int count = n - m + 1;
19 | //找到倒转链表左结点的前面一个结点
20 | while (m > 1){
21 | m--;
22 | index = index.next;
23 | }
24 | left = index;
25 | index = index.next;
26 | right = index;
27 | left.next = null;
28 |
29 | while (count > 0){
30 | count--;
31 | tmp = index;
32 | index = index.next;
33 | tmp.next = left.next;
34 | left.next = tmp;
35 | }
36 |
37 | //连接右半部分
38 | right.next = index;
39 |
40 | return left == dummy ? left.next : head;
41 | }
42 |
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/str/LongestSubstring.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.str;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | /**
7 | * @author TommyYang on 2019-04-08
8 | */
9 | public class LongestSubstring {
10 |
11 | public int lengthofLongestSubstring(String s){
12 | int i = 0, j = 0, maxLen = 0;
13 | Set set = new HashSet();
14 | int n = s.length();
15 | while (i < n && j < n){
16 | if (!set.contains(s.charAt(j))){
17 | set.add(s.charAt(j++));
18 | maxLen = Math.max(maxLen, j - i);
19 | } else {
20 | set.remove(s.charAt(i++));
21 | }
22 | }
23 | return maxLen;
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/str/ReverseInt.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.str;
2 |
3 | /**
4 | * @author TommyYang on 2019-04-08
5 | */
6 | public class ReverseInt {
7 |
8 | public int reverse(int x) {
9 | long res = 0;
10 | while (x != 0){
11 | res = res * 10 + x % 10;
12 | res /= 10;
13 | }
14 |
15 | if (res > Integer.MAX_VALUE || res < Integer.MIN_VALUE){
16 | return 0;
17 | }
18 |
19 | return (int)res;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/tree/InvertTree.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.tree;
2 |
3 | /**
4 | * @author TommyYang on 2019-05-08
5 | */
6 | //翻转一棵二叉树。
7 | public class InvertTree {
8 |
9 | public TreeNode invertTree(TreeNode root) {
10 | if (root == null){
11 | return root;
12 | }
13 |
14 | TreeNode tmp = root.left;
15 | root.left = root.right;
16 | root.right = tmp;
17 |
18 | invertTree(root.left);
19 | invertTree(root.right);
20 |
21 | return root;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/tree/MergeTwoBTree.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.tree;
2 |
3 | /**
4 | * @author TommyYang on 2019-03-22
5 | */
6 | public class MergeTwoBTree {
7 |
8 | public static void main(String[] args) {
9 | TreeNode root1 = new TreeNode(1);
10 | TreeNode t1 = new TreeNode(2);
11 | TreeNode t2 = new TreeNode(3);
12 | TreeNode t3 = new TreeNode(4);
13 |
14 | TreeNode root2 = new TreeNode(5);
15 | TreeNode t4 = new TreeNode(4);
16 | TreeNode t5 = new TreeNode(3);
17 | TreeNode t6 = new TreeNode(2);
18 |
19 | root1.left = t1;
20 | t1.left = t2;
21 | t1.right = t3;
22 |
23 | root2.right = t4;
24 | t4.left = t5;
25 | t5.right = t6;
26 |
27 | TreeNode resNode = mergeTrees2(t1, t4);
28 | displayTree(resNode);
29 | }
30 |
31 | //以t1为存储结果的TreeNode
32 | public static TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
33 | if(t1 == null){
34 | return t2;
35 | }
36 | if (t2 == null){
37 | return t1;
38 | }
39 | t1.val += t2.val;
40 | t1.left = mergeTrees(t1.left, t2.left);
41 | t1.right = mergeTrees(t1.right, t2.right);
42 | return t1;
43 | }
44 |
45 | //新建一个TreeNode来存储结果
46 | public static TreeNode mergeTrees2(TreeNode t1, TreeNode t2){
47 | if(t1 == null && t2 == null){
48 | return null;
49 | }
50 |
51 | TreeNode root = new TreeNode((t1 == null ? 0 : t1.val) + (t2 == null ? 0 : t2.val));
52 | root.left = mergeTrees2((t1 == null ? null : t1.left), (t2 == null ? null : t2.left));
53 | root.right = mergeTrees2((t1 == null ? null : t1.right), (t2 == null ? null : t2.right));
54 | return root;
55 | }
56 |
57 | public static void displayTree(TreeNode node){
58 | if (node == null){
59 | return;
60 | }
61 | System.out.println(node.val);
62 | displayTree(node.left);
63 | displayTree(node.right);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/tree/TreeNode.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.tree;
2 |
3 | /**
4 | * @author TommyYang on 2019-03-22
5 | */
6 | public class TreeNode {
7 |
8 | public int val;
9 |
10 | public TreeNode left;
11 |
12 | public TreeNode right;
13 |
14 | public TreeNode(int val) {
15 | this.val = val;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/codeinterview/src/main/java/cn/tommyyang/tree/ValidBST.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.tree;
2 |
3 | /**
4 | * @author TommyYang on 2019-03-28
5 | */
6 | public class ValidBST {
7 |
8 |
9 | public static void main(String[] args) {
10 | TreeNode t1 = new TreeNode(10);
11 | TreeNode t2 = new TreeNode(5);
12 |
13 | TreeNode t3 = new TreeNode(15);
14 | TreeNode t4 = new TreeNode(6);
15 | TreeNode t5 = new TreeNode(20);
16 |
17 | t1.left = t2;
18 | t1.right = t3;
19 | t3.left = t4;
20 | t3.right = t5;
21 |
22 | new ValidBST().isValidBST(t1);
23 | }
24 |
25 |
26 | double last = -Double.MAX_VALUE;
27 | public boolean isValidBST(TreeNode root) {
28 | if (root == null) {
29 | return true;
30 | }
31 | if (isValidBST(root.left)) {
32 | if (last < root.val) {
33 | last = root.val;
34 | return isValidBST(root.right);
35 | }
36 | }
37 | return false;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/img/AB测试.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/img/AB测试.png
--------------------------------------------------------------------------------
/io/README.md:
--------------------------------------------------------------------------------
1 | # IO 篇
2 |
3 | 该模块主要是介绍 `IO` 方面的知识;
4 | - `NIO`, `AIO`;
5 | - 网络编程相关;
6 | - 多线程、多核 CPU、进程之间的关系(因为这些跟 IO 都有关系,所有放在该篇来介绍)。
7 |
8 | ## NIO 和 AIO
9 | 主要会用 `JDK` 原始 `NIO`、 `AIO` 相关 `API` 去实现 `Socket` 网路编程小实例;
10 | 以及使用 `Netty` 实现网络编程的小实例;然后说明一些使用 `Netty` 的好处。
11 |
12 |
13 | ### `Linux` 系统 `IO` 模型介绍
14 | //TODO
15 |
16 | ### `IO` 相关 `API` 介绍
17 | //TODO
18 |
19 | ### `NIO` 相关 `API` 介绍
20 | //TODO
21 |
22 | ### `AIO` 相关 `API` 介绍
23 | //TODO
24 |
25 |
--------------------------------------------------------------------------------
/io/Thread-CPU-Process.md:
--------------------------------------------------------------------------------
1 | # 多线程、进程、多核 CPU 详细介绍
2 | 进程和线程的区别是什么?相信大家可能会经常会被问到这个问题;虽然看起来是一个简单的问题,但是都有可能是模棱两可的回答。下面我们从内核的角度来看看进程是什么?
3 |
--------------------------------------------------------------------------------
/io/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | javainterview
7 | cn.tommyyang
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | io
13 |
14 |
15 |
16 | io.netty
17 | netty-all
18 | 5.0.0.Alpha2
19 |
20 |
21 |
22 |
23 |
24 |
25 | org.apache.maven.plugins
26 | maven-compiler-plugin
27 |
28 | 1.8
29 | 1.8
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/aio/AcceptCompletionHandler.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.aio;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.nio.channels.AsynchronousSocketChannel;
5 | import java.nio.channels.CompletionHandler;
6 |
7 | /**
8 | * @author TommyYang on 2019-05-20
9 | */
10 | public class AcceptCompletionHandler implements CompletionHandler {
11 |
12 | @Override
13 | public void completed(AsynchronousSocketChannel result, AsyncTimeServerHandler attachment) {
14 | attachment.asyncServerSocketChannel.accept(attachment, this);
15 | ByteBuffer buffer = ByteBuffer.allocate(1024);
16 | result.read(buffer, buffer, new ReadCompletionHandler(result));
17 | }
18 |
19 | @Override
20 | public void failed(Throwable exc, AsyncTimeServerHandler attachment) {
21 | exc.printStackTrace();
22 | attachment.latch.countDown();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/aio/AsyncTimeClientHandler.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.aio;
2 |
3 | import java.io.IOException;
4 | import java.io.UnsupportedEncodingException;
5 | import java.net.InetSocketAddress;
6 | import java.nio.ByteBuffer;
7 | import java.nio.channels.AsynchronousSocketChannel;
8 | import java.nio.channels.CompletionHandler;
9 | import java.util.concurrent.CountDownLatch;
10 |
11 | /**
12 | * @author TommyYang on 2019-05-21
13 | */
14 | public class AsyncTimeClientHandler implements CompletionHandler, Runnable {
15 |
16 | private String host;
17 | private int port;
18 | private AsynchronousSocketChannel timeClient;
19 | private CountDownLatch latch;
20 |
21 | public AsyncTimeClientHandler(String host, int port) {
22 | this.host = host;
23 | this.port = port;
24 | try {
25 | this.timeClient = AsynchronousSocketChannel.open();
26 | } catch (IOException e) {
27 | e.printStackTrace();
28 | }
29 | }
30 |
31 | @Override
32 | public void completed(Void result, AsyncTimeClientHandler attachment) {
33 | byte[] req = "QUERY TIME ORDER".getBytes();
34 | ByteBuffer reqBuffer = ByteBuffer.allocate(req.length);
35 | reqBuffer.put(req);
36 | reqBuffer.flip();
37 |
38 | this.timeClient.write(reqBuffer, reqBuffer, new CompletionHandler() {
39 | @Override
40 | public void completed(Integer result, ByteBuffer attachment) {
41 | if (attachment.hasRemaining()){
42 | timeClient.write(attachment, attachment, this);
43 | } else {
44 | ByteBuffer respBuffer = ByteBuffer.allocate(1024);
45 | timeClient.read(respBuffer, respBuffer, new CompletionHandler() {
46 | @Override
47 | public void completed(Integer result, ByteBuffer attachment) {
48 | attachment.flip();
49 | byte[] respBytes = new byte[attachment.remaining()];
50 | attachment.get(respBytes);
51 | try {
52 | String respBody = new String(respBytes, "UTF-8");
53 | System.out.println("Now is:" + respBody);
54 | } catch (UnsupportedEncodingException e) {
55 | e.printStackTrace();
56 | }
57 | }
58 |
59 | @Override
60 | public void failed(Throwable exc, ByteBuffer attachment) {
61 | exc.printStackTrace();
62 | close();
63 | }
64 | });
65 | }
66 | }
67 |
68 | @Override
69 | public void failed(Throwable exc, ByteBuffer attachment) {
70 | exc.printStackTrace();
71 | close();
72 | }
73 | });
74 | }
75 |
76 | @Override
77 | public void failed(Throwable exc, AsyncTimeClientHandler attachment) {
78 | exc.printStackTrace();
79 | this.close();
80 | }
81 |
82 | @Override
83 | public void run() {
84 | this.latch = new CountDownLatch(1);
85 | this.timeClient.connect(new InetSocketAddress(this.host, this.port), this, this);
86 |
87 | try {
88 | this.latch.await();//让当前client执行线程一直处于挂起状态,直到当前线程执行完毕,latch 释放。
89 | } catch (InterruptedException e) {
90 | e.printStackTrace();
91 | }
92 |
93 | try {
94 | this.timeClient.close();
95 | } catch (IOException e) {
96 | e.printStackTrace();
97 | }
98 |
99 | }
100 |
101 | private void close(){
102 | try {
103 | timeClient.close();
104 | } catch (IOException e) {
105 | e.printStackTrace();
106 | }
107 | latch.countDown();
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/aio/AsyncTimeServerHandler.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.aio;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.nio.channels.AsynchronousServerSocketChannel;
6 | import java.util.concurrent.CountDownLatch;
7 |
8 | /**
9 | * @author TommyYang on 2019-05-20
10 | */
11 | public class AsyncTimeServerHandler implements Runnable {
12 |
13 | private int port;
14 |
15 | CountDownLatch latch;
16 | AsynchronousServerSocketChannel asyncServerSocketChannel;
17 |
18 | public AsyncTimeServerHandler(int port) {
19 | this.port = port;
20 | try {
21 | this.asyncServerSocketChannel = AsynchronousServerSocketChannel.open();
22 | this.asyncServerSocketChannel.bind(new InetSocketAddress(this.port));
23 | System.out.println("The time server is start in port:" + port);
24 | } catch (IOException e) {
25 | e.printStackTrace();
26 | }
27 | }
28 |
29 | public void run() {
30 | this.latch = new CountDownLatch(1);
31 | doAccept();
32 | try {
33 | this.latch.await();
34 | } catch (InterruptedException e) {
35 | e.printStackTrace();
36 | }
37 | }
38 |
39 | private void doAccept(){
40 | this.asyncServerSocketChannel.accept(this, new AcceptCompletionHandler());
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/aio/ReadCompletionHandler.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.aio;
2 |
3 | import java.io.IOException;
4 | import java.io.UnsupportedEncodingException;
5 | import java.nio.ByteBuffer;
6 | import java.nio.channels.AsynchronousSocketChannel;
7 | import java.nio.channels.CompletionHandler;
8 | import java.util.Date;
9 |
10 | /**
11 | * @author TommyYang on 2019-05-20
12 | */
13 | public class ReadCompletionHandler implements CompletionHandler {
14 |
15 | private AsynchronousSocketChannel channel;
16 |
17 | public ReadCompletionHandler(AsynchronousSocketChannel channel) {
18 | if (this.channel == null){
19 | this.channel = channel;
20 | }
21 | }
22 |
23 | @Override
24 | public void completed(Integer result, ByteBuffer attachment) {
25 | attachment.flip();
26 | byte[] body = new byte[attachment.remaining()];
27 | attachment.get(body);
28 |
29 | try {
30 | String req = new String(body, "utf-8");
31 | System.out.println("The Time Server receive order :" + req);
32 | String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(req) ? new Date().toString()
33 | : "BAD ORDER";
34 | doWrite(currentTime);
35 | } catch (UnsupportedEncodingException e) {
36 | e.printStackTrace();
37 | }
38 | }
39 |
40 | @Override
41 | public void failed(Throwable exc, ByteBuffer attachment) {
42 | try {
43 | this.channel.close();
44 | } catch (IOException e) {
45 | e.printStackTrace();
46 | }
47 | }
48 |
49 | private void doWrite(String resp){
50 | if (resp != null && resp.trim().length() > 0){
51 | byte[] respBytes = resp.getBytes();
52 | ByteBuffer writeBuffer = ByteBuffer.allocate(respBytes.length);
53 | writeBuffer.put(respBytes);
54 | writeBuffer.flip();
55 | this.channel.write(writeBuffer, writeBuffer, new CompletionHandler() {
56 | @Override
57 | public void completed(Integer result, ByteBuffer attachment) {
58 | if (attachment.hasRemaining()){
59 | channel.write(writeBuffer, writeBuffer, this);
60 | }
61 | }
62 |
63 | @Override
64 | public void failed(Throwable exc, ByteBuffer attachment) {
65 | try {
66 | channel.close();
67 | } catch (IOException e) {
68 | e.printStackTrace();
69 | }
70 | }
71 | });
72 | }
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/aio/TimeClient.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.aio;
2 |
3 | /**
4 | * @author TommyYang on 2019-05-21
5 | */
6 | public class TimeClient {
7 |
8 | public static void main(String[] args) {
9 | int port = 8000;
10 | if (args != null && args.length > 1) {
11 | port = Integer.valueOf(args[0]);
12 | }
13 | for (int i = 0; i < 10; i++)
14 | new Thread(new AsyncTimeClientHandler("127.0.0.1", port), "AIO-AsyncTimeClient-001").start();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/aio/TimeServer.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.aio;
2 |
3 | /**
4 | * @author TommyYang on 2019-05-21
5 | */
6 | public class TimeServer {
7 |
8 | public static void main(String[] args) {
9 | int port = 8000;
10 | if (args != null && args.length == 1){
11 | try {
12 | port = Integer.valueOf(args[0]);
13 | } catch (NumberFormatException e){
14 | e.printStackTrace();
15 | System.out.println("param is error, please set port of time server!!!");
16 | }
17 | }
18 | AsyncTimeServerHandler timeServerHandler = new AsyncTimeServerHandler(port);
19 |
20 | new Thread(timeServerHandler, "AIO-AsyncTimeServer-001").start();
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/file/BigFileWriter.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.file;
2 |
3 | import java.io.BufferedWriter;
4 | import java.io.FileOutputStream;
5 | import java.io.OutputStreamWriter;
6 |
7 | /**
8 | * @Author : TommyYang
9 | * @Time : 2019-09-09 16:36
10 | * @Software: IntelliJ IDEA
11 | * @File : BigFileWriter.java
12 | */
13 | public class BigFileWriter {
14 |
15 | private FileOutputStream outStream = null;
16 | private BufferedWriter bfWriter = null;
17 |
18 | private String filePath;
19 |
20 | public BigFileWriter(String filePath) {
21 | this.filePath = filePath;
22 | open();
23 | }
24 |
25 | private void open() {
26 | try {
27 | outStream = new FileOutputStream(this.filePath, true);
28 | bfWriter = new BufferedWriter(new OutputStreamWriter(outStream, "UTF-8"));
29 | } catch (Exception e) {
30 | System.out.println("get big file writer error");
31 | e.printStackTrace();
32 | }
33 | }
34 |
35 | public void writeFile(String content) {
36 | try {
37 | bfWriter.write(content);
38 | } catch (Exception e) {
39 | e.printStackTrace();
40 | }
41 | }
42 |
43 | public void close() {
44 | try {
45 | if (bfWriter != null) {
46 | bfWriter.close();
47 | }
48 | if (outStream != null) {
49 | outStream.close();
50 | }
51 | } catch (Exception e) {
52 | e.printStackTrace();
53 | }
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/file/BigFileWriter1.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.file;
2 |
3 | import java.io.BufferedWriter;
4 | import java.io.FileOutputStream;
5 | import java.io.OutputStreamWriter;
6 |
7 | /**
8 | * @Author : TommyYang
9 | * @Time : 2019-09-09 18:15
10 | * @Software: IntelliJ IDEA
11 | * @File : BigFileWriter1.java
12 | */
13 | public class BigFileWriter1 {
14 |
15 | private FileOutputStream outStream = null;
16 | private BufferedWriter bfWriter = null;
17 |
18 | private String filePath;
19 |
20 | public BigFileWriter1(String filePath) {
21 | this.filePath = filePath;
22 | open();
23 | }
24 |
25 | private void open() {
26 | try {
27 | outStream = new FileOutputStream(this.filePath, true);
28 | bfWriter = new BufferedWriter(new OutputStreamWriter(outStream, "UTF-8"));
29 | } catch (Exception e) {
30 | System.out.println("get big file writer error");
31 | e.printStackTrace();
32 | }
33 | }
34 |
35 | public synchronized void writeFile(String content) {
36 | try {
37 | bfWriter.write(content);
38 | } catch (Exception e) {
39 | e.printStackTrace();
40 | }
41 | }
42 |
43 | public void close() {
44 | try {
45 | if (bfWriter != null) {
46 | bfWriter.close();
47 | }
48 | if (outStream != null) {
49 | outStream.close();
50 | }
51 | } catch (Exception e) {
52 | e.printStackTrace();
53 | }
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/file/FileTest.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.file;
2 |
3 | import java.util.stream.IntStream;
4 |
5 | /**
6 | * @Author : TommyYang
7 | * @Time : 2019-09-09 23:30
8 | * @Software: IntelliJ IDEA
9 | * @File : FileTest.java
10 | */
11 | public class FileTest {
12 |
13 | public static void main(String[] args) {
14 | new Thread(()-> {
15 | long startTime = System.currentTimeMillis();
16 | BigFileWriter fileWriter = new BigFileWriter("/Users/tommy/Documents/aa.txt");
17 | IntStream.range(0, 500000).parallel().forEach(index -> fileWriter.writeFile("user:" + index + "\n"));
18 | fileWriter.close();
19 | long endTime = System.currentTimeMillis();
20 | System.out.println("big file writer const:" + (endTime - startTime) + " ms");
21 | }).start();
22 |
23 | new Thread(()-> {
24 | long startTime = System.currentTimeMillis();
25 | BigFileWriter1 fileWriter = new BigFileWriter1("/Users/tommy/Documents/bb.txt");
26 | IntStream.range(0, 500000).parallel().forEach(index -> fileWriter.writeFile("user:" + index + "\n"));
27 | fileWriter.close();
28 | long endTime = System.currentTimeMillis();
29 | System.out.println("big file writer 1 const:" + (endTime - startTime) + " ms");
30 | }).start();
31 |
32 |
33 | new Thread(()-> {
34 | long startTime = System.currentTimeMillis();
35 | IntStream.range(0, 500000).parallel().forEach(index -> FileUtils.writeFile("/Users/tommy/Documents/cc.txt", "user:" + index + "\n"));
36 | long endTime = System.currentTimeMillis();
37 | System.out.println("file utils const:" + (endTime - startTime) + " ms");
38 | }).start();
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/file/FileUtils.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.file;
2 |
3 | import java.io.BufferedWriter;
4 | import java.io.FileOutputStream;
5 | import java.io.OutputStreamWriter;
6 |
7 | /**
8 | * @Author : TommyYang
9 | * @Time : 2019-09-09 16:36
10 | * @Software: IntelliJ IDEA
11 | * @File : FileUtils.java
12 | */
13 | public class FileUtils {
14 |
15 | public static synchronized void writeFile(String filePath, String content) {
16 | FileOutputStream outStream = null;
17 | BufferedWriter bfWriter = null;
18 | try {
19 | outStream = new FileOutputStream(filePath, true);
20 | bfWriter = new BufferedWriter(new OutputStreamWriter(outStream, "UTF-8"));
21 | bfWriter.write(content);
22 | } catch (Exception e) {
23 | e.printStackTrace();
24 | } finally {
25 | try {
26 | if (bfWriter != null) {
27 | bfWriter.close();
28 | }
29 | if (outStream != null) {
30 | outStream.close();
31 | }
32 | } catch (Exception e) {
33 |
34 | }
35 | }
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/nettynio/TimeClient.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.nettynio;
2 |
3 | import io.netty.bootstrap.Bootstrap;
4 | import io.netty.channel.ChannelFuture;
5 | import io.netty.channel.ChannelInitializer;
6 | import io.netty.channel.ChannelOption;
7 | import io.netty.channel.EventLoopGroup;
8 | import io.netty.channel.nio.NioEventLoopGroup;
9 | import io.netty.channel.socket.SocketChannel;
10 | import io.netty.channel.socket.nio.NioSocketChannel;
11 |
12 | /**
13 | * @author TommyYang on 2019-05-21
14 | */
15 | public class TimeClient {
16 |
17 | private void connect(String host, int port) throws Exception{
18 | //配置客户端NIO线程组
19 | EventLoopGroup group = new NioEventLoopGroup();
20 |
21 | Bootstrap bootstrap = new Bootstrap();
22 | bootstrap.group(group)
23 | .channel(NioSocketChannel.class)
24 | .option(ChannelOption.TCP_NODELAY, true)
25 | .handler(new ChannelInitializer() {
26 | @Override
27 | protected void initChannel(SocketChannel socketChannel) throws Exception {
28 | socketChannel.pipeline().addLast(new TimeClientHandler());
29 | }
30 | });
31 |
32 | //发起异步连接操作
33 | ChannelFuture cf = bootstrap.connect(host, port).sync();
34 |
35 | //等待 客户端链路关闭
36 | cf.channel().closeFuture().sync();
37 | }
38 |
39 | public static void main(String[] args) throws Exception {
40 | int port = 8080;
41 |
42 | new TimeClient().connect("127.0.0.1", port);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/nettynio/TimeClientHandler.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.nettynio;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.buffer.Unpooled;
5 | import io.netty.channel.ChannelHandlerAdapter;
6 | import io.netty.channel.ChannelHandlerContext;
7 |
8 | /**
9 | * @author TommyYang on 2019-05-22
10 | */
11 | public class TimeClientHandler extends ChannelHandlerAdapter {
12 |
13 | private final ByteBuf msg;
14 |
15 | public TimeClientHandler() {
16 | byte[] req = "QUERY TIME ORDER".getBytes();
17 | this.msg = Unpooled.buffer(req.length);
18 | this.msg.writeBytes(req);
19 | }
20 |
21 | @Override
22 | public void channelActive(ChannelHandlerContext ctx) throws Exception {
23 | ctx.writeAndFlush(this.msg);
24 | }
25 |
26 | @Override
27 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
28 | ByteBuf resp = (ByteBuf)msg;
29 | byte[] respBytes = new byte[resp.readableBytes()];
30 | resp.readBytes(respBytes);
31 |
32 | System.out.println("Now is:" + new String(respBytes, "UTF-8"));
33 |
34 | //查询完毕,释放资源,结束程序
35 | ctx.close();
36 |
37 | }
38 |
39 | @Override
40 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
41 | //释放资源
42 | ctx.close();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/nettynio/TimeServer.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.nettynio;
2 |
3 | import io.netty.bootstrap.ServerBootstrap;
4 | import io.netty.channel.ChannelFuture;
5 | import io.netty.channel.ChannelInitializer;
6 | import io.netty.channel.ChannelOption;
7 | import io.netty.channel.EventLoopGroup;
8 | import io.netty.channel.nio.NioEventLoopGroup;
9 | import io.netty.channel.socket.SocketChannel;
10 | import io.netty.channel.socket.nio.NioServerSocketChannel;
11 |
12 | /**
13 | * @author TommyYang on 2019-05-21
14 | */
15 | public class TimeServer {
16 |
17 | private void bind(int port) throws Exception{
18 |
19 | EventLoopGroup bossGroup = new NioEventLoopGroup();
20 | EventLoopGroup workGroup = new NioEventLoopGroup();
21 |
22 | try {
23 | ServerBootstrap bootstrap = new ServerBootstrap();
24 | bootstrap.group(bossGroup, workGroup)
25 | .channel(NioServerSocketChannel.class)
26 | .option(ChannelOption.SO_BACKLOG, 1024)
27 | .childHandler(new ChildChannelHandler());
28 |
29 | //绑定端口,同步等待成功
30 | ChannelFuture cf = bootstrap.bind(port).sync();
31 |
32 | System.out.println("Netty Nio server start-001");
33 |
34 | //等待服务端监听端口关闭
35 | cf.channel().closeFuture().sync();
36 | } finally {
37 | //优雅的退出
38 | bossGroup.shutdownGracefully();
39 | workGroup.shutdownGracefully();
40 | }
41 |
42 | }
43 |
44 | private class ChildChannelHandler extends ChannelInitializer{
45 |
46 | @Override
47 | protected void initChannel(SocketChannel socketChannel) throws Exception {
48 | socketChannel.pipeline().addLast(new TimeServerHandler());
49 | }
50 |
51 | }
52 |
53 | public static void main(String[] args) throws Exception {
54 | int port = 8080;
55 |
56 | if (args != null && args.length > 0){
57 | try {
58 | port = Integer.valueOf(args[0]);
59 | } catch (NumberFormatException e){
60 | e.printStackTrace();
61 | }
62 |
63 | }
64 |
65 | new TimeServer().bind(port);
66 |
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/nettynio/TimeServerHandler.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.nettynio;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.buffer.Unpooled;
5 | import io.netty.channel.ChannelHandlerAdapter;
6 | import io.netty.channel.ChannelHandlerContext;
7 |
8 | import java.util.Date;
9 |
10 | /**
11 | * @author TommyYang on 2019-05-21
12 | */
13 | public class TimeServerHandler extends ChannelHandlerAdapter {
14 |
15 | @Override
16 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
17 | ByteBuf buf = (ByteBuf)msg;
18 | byte[] req = new byte[buf.readableBytes()];
19 | buf.readBytes(req);//读取buf中的数据到byte[]
20 |
21 | String body = new String(req, "UTF-8");
22 | String currentTime = body.equalsIgnoreCase("QUERY TIME ORDER") ? new Date().toString() : "BAD ORDER";
23 |
24 | ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
25 | ctx.write(resp);
26 | }
27 |
28 | @Override
29 | public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
30 | ctx.flush();
31 | }
32 |
33 | @Override
34 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
35 | cause.printStackTrace();
36 | ctx.close();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/nio/TimeClient.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.nio;
2 |
3 | /**
4 | * @author TommyYang on 2019-05-09
5 | */
6 | public class TimeClient {
7 | public static void main(String[] args) {
8 | int port = 8000;
9 | if (args != null && args.length == 1){
10 | try {
11 | port = Integer.parseInt(args[0]);
12 | } catch (Exception e){
13 | e.printStackTrace();
14 | System.out.println("param is error, please set port of time client!!!");
15 | }
16 | }
17 | for(int i = 0; i < 10; i++)
18 | new Thread(new TimeClientHandler("127.0.0.1", port), "NIO-TimeClient-001").start();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/io/src/main/java/cn/tommyyang/nio/TimeServer.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.nio;
2 |
3 | /**
4 | * @author TommyYang on 2019-05-09
5 | */
6 | public class TimeServer {
7 |
8 | public static void main(String[] args) {
9 | int port = 8000;
10 | if (args != null && args.length == 1){
11 | try {
12 | port = Integer.parseInt(args[0]);
13 | } catch (Exception e){
14 | e.printStackTrace();
15 | System.out.println("param is error, please set port of time server!!!");
16 | }
17 | }
18 |
19 | MultiplexerTimeServer timeServer = new MultiplexerTimeServer(port);
20 | new Thread(timeServer, "NIO-MultiplexerTimeServer-001").start();
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/javabase/README.md:
--------------------------------------------------------------------------------
1 | # Java 基础知识
2 |
3 | ## 基础
4 | ### Integer类
5 | ```java
6 |
7 | public class Test {
8 | public static void main(String[] args){
9 | Integer a = new Integer(129);
10 | Integer b = new Integer(129);
11 |
12 | // 1
13 | System.out.println(a == b);
14 |
15 |
16 | Integer c = new Integer(127);
17 | Integer d = new Integer(127);
18 | // 2
19 | System.out.println(c == d);
20 | }
21 | }
22 |
23 | ```
24 |
25 | 上述代码可以看出1处 输出 false; 2 处输出 true。
26 | 从Integer类源码中,有一个内部类,代码如下:
27 | ```java
28 |
29 | private static class IntegerCache {
30 | static final int low = -128;
31 | static final int high;
32 | static final Integer cache[];
33 |
34 | static {
35 | // high value may be configured by property
36 | int h = 127;
37 | String integerCacheHighPropValue =
38 | sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
39 | if (integerCacheHighPropValue != null) {
40 | try {
41 | int i = parseInt(integerCacheHighPropValue);
42 | i = Math.max(i, 127);
43 | // Maximum array size is Integer.MAX_VALUE
44 | h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
45 | } catch( NumberFormatException nfe) {
46 | // If the property cannot be parsed into an int, ignore it.
47 | }
48 | }
49 | high = h;
50 |
51 | cache = new Integer[(high - low) + 1];
52 | int j = low;
53 | for(int k = 0; k < cache.length; k++)
54 | cache[k] = new Integer(j++);
55 |
56 | // range [-128, 127] must be interned (JLS7 5.1.7)
57 | assert IntegerCache.high >= 127;
58 | }
59 |
60 | private IntegerCache() {}
61 | }
62 |
63 | ```
64 | 从上述源码可以找出出现上述1处、2处结果的原因。
65 |
66 |
67 | ### Calendar类
68 | > 添加天数:DAY_OF_MONTH、DAY_OF_YEAR、DAY_OF_WEEK、DAY_OF_WEEK_IN_MONTH的区别
69 |
70 | 就单纯的add操作结果都一样,因为都是将日期+1, 不管是月的日期中加1还是年的日期中加1。
71 | 强行解释区别如下:
72 | - `DAY_OF_MONTH` 的主要作用是get(DAY_OF_MONTH),用来获得这一天在是这个月的第多少天。
73 | - `DAY_OF_YEAR` 的主要作用get(DAY_OF_YEAR),用来获得这一天在是这个年的第多少天。
74 | - 同样,`DAY_OF_WEEK`,用来获得当前日期是一周的第几天;`DAY_OF_WEEK_IN_MONTH`,用来获取 day 所在的周是这个月的第几周
75 |
76 | ### [String、StringBuilder和StringBuffer](stringbuilderandstringbuffer.md)
77 | | 类名| 描述| 是否可| 线程安全性|
78 | |:---- |:---- |:---- |:---- |
79 | |String |字符串常量 | 不可变类 | 线程安全 |
80 | |StringBuilder |字符串变量 | 可变类 | 线程不安全 |
81 | |StringBuffer |字符串变量 | 可变类 | 线程安全 |
82 |
83 | ### [关键字篇](keywords)
84 | - [transient](keywords/transient.md)
85 | - [volatile](keywords/volatile.md)
86 |
87 |
88 | ## [异常篇](exception.md)
89 |
90 | ## [Java8 篇](java8)
91 |
92 | ## :house_with_garden: [数据结构篇](datastructure)
93 | - [BlockingQueue和BlockingDeque](datastructure/blockingqueueanddeque.md)
94 | * Queue
95 | * Deque
96 | * LinkedList
97 | * ArrayBlockingQueue
98 | * LinkedBlockingQueue
99 | * LinkedBlockingDeque
100 |
101 | ## 多线程相关
102 | - [线程池](threadpool.md)
103 |
104 |
--------------------------------------------------------------------------------
/javabase/datastructure/README.md:
--------------------------------------------------------------------------------
1 | # 数据结构篇
2 |
3 | ## [BlockingQueue](blockingqueueanddeque.md)
4 |
5 | ## [线程池相关](../threadpool.md)
--------------------------------------------------------------------------------
/javabase/datastructure/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | javainterview
7 | cn.tommyyang
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | datastructure
13 |
14 |
15 |
16 | org.apache.maven.plugins
17 | maven-compiler-plugin
18 |
19 | 1.17
20 | 1.17
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/javabase/datastructure/src/main/java/cn/tommyyang/RunTest.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang;
2 |
3 | import cn.tommyyang.forkjoinpool.CountTask;
4 |
5 | import java.util.*;
6 | import java.util.concurrent.*;
7 | import java.util.concurrent.locks.Condition;
8 | import java.util.concurrent.locks.ReentrantLock;
9 |
10 | /**
11 | * @author TommyYang on 2019-04-12
12 | */
13 | public class RunTest {
14 |
15 | public static void main(String[] args) throws ExecutionException, InterruptedException {
16 | // runForkJoinPool();
17 |
18 | Thread t = new Thread(()->
19 | System.out.println("aa")
20 | );
21 |
22 | t.start();
23 | t.start();
24 | }
25 |
26 | private static void runForkJoinPool() throws ExecutionException, InterruptedException {
27 | ForkJoinPool forkJoinPool = new ForkJoinPool(5);
28 | List arrs = new ArrayList<>(100000);
29 | for (int i = 1; i <= 100000; i++) {
30 | arrs.add(i);
31 | }
32 |
33 | CountTask countTask = new CountTask(arrs, 0, arrs.size() - 1);
34 |
35 | Future r1 = forkJoinPool.submit(countTask);
36 | System.out.println(r1.get());
37 | ExecutorService service = Executors.newWorkStealingPool(1);
38 | service.execute(() -> System.out.println("aa"));
39 | // ThreadPoolExecutor
40 | // Math
41 | // LinkedBlockingQueue
42 | // HashMap
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/javabase/datastructure/src/main/java/cn/tommyyang/forkjoinpool/CountTask.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.forkjoinpool;
2 |
3 | import java.util.List;
4 | import java.util.concurrent.RecursiveTask;
5 |
6 | /**
7 | * @author TommyYang on 2019-04-23
8 | */
9 | public class CountTask extends RecursiveTask {
10 |
11 | private final static int THRESHOLD = 10000;
12 |
13 | private List list;
14 | private int start;
15 | private int end;
16 |
17 | public CountTask(List list, int start, int end) {
18 | this.list = list;
19 | this.start = start;
20 | this.end = end;
21 | }
22 |
23 | @Override
24 | protected Integer compute() {
25 | int sum = 0;
26 |
27 | boolean canCompute = (this.end - this.start) <= THRESHOLD;
28 | if (canCompute) {
29 | System.out.println(this.start + "--" + this.end);
30 | for (int i = this.start; i <= this.end; i++){
31 | sum += this.list.get(i);
32 | }
33 | System.out.println(sum);
34 | } else {
35 | int mid = (this.start + this.end) / 2;
36 | CountTask leftTask = new CountTask(this.list, this.start, mid);
37 | CountTask rightTask = new CountTask(this.list, mid + 1, this.end);
38 |
39 | leftTask.fork();
40 | rightTask.fork();
41 |
42 | int leftResult = leftTask.join();
43 | int rightResult = rightTask.join();
44 |
45 | sum = leftResult + rightResult;
46 | }
47 |
48 | return sum;
49 | }
50 |
51 |
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/javabase/datastructure/src/main/java/cn/tommyyang/queue/ArrayBlockingQueueDemo.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.queue;
2 |
3 | /**
4 | * @Author : TommyYang
5 | * @Time : 2019-06-13 18:23
6 | * @Software: IntelliJ IDEA
7 | * @File : ArrayBlockingQueueDemo.java
8 | */
9 |
10 | import java.util.concurrent.ArrayBlockingQueue;
11 | import java.util.concurrent.ExecutorService;
12 | import java.util.concurrent.Executors;
13 |
14 | /**
15 | * 使用 ArrayBlockingQueue 实现的生产者消费者简单模型
16 | */
17 | public class ArrayBlockingQueueDemo {
18 |
19 | private final static ExecutorService THREAD_POOL = Executors.newFixedThreadPool(4);
20 | private final static ArrayBlockingQueue QUEUE = new ArrayBlockingQueue<>(1);
21 |
22 | public static void main(String[] args) {
23 | THREAD_POOL.execute(new Producer(QUEUE));
24 | THREAD_POOL.execute(new Consumer(QUEUE));
25 | THREAD_POOL.execute(new Producer(QUEUE));
26 | THREAD_POOL.execute(new Consumer(QUEUE));
27 | THREAD_POOL.shutdown();
28 | }
29 | }
30 |
31 | class Data {
32 |
33 | }
34 |
35 | class Producer implements Runnable {
36 |
37 | private final ArrayBlockingQueue mAbq;
38 |
39 | public Producer(ArrayBlockingQueue mAbq) {
40 | this.mAbq = mAbq;
41 | }
42 |
43 | @Override
44 | public void run() {
45 | for (int i = 0; i < 10; i++) {
46 | produce();
47 | }
48 |
49 | }
50 |
51 | private void produce() {
52 | try {
53 | Data data = new Data();
54 | this.mAbq.put(data);
55 | System.out.println("生产了数据@" + data);
56 | } catch (InterruptedException e) {
57 | e.printStackTrace();
58 | }
59 | }
60 | }
61 |
62 | class Consumer implements Runnable {
63 |
64 | private final ArrayBlockingQueue mAbq;
65 |
66 | public Consumer(ArrayBlockingQueue mAbq) {
67 | this.mAbq = mAbq;
68 | }
69 |
70 | @Override
71 | public void run() {
72 | for (int i = 0; i < 10; i++) {
73 | consumer();
74 | }
75 | }
76 |
77 | private void consumer() {
78 | try {
79 | Data data = this.mAbq.take();
80 | System.out.println("消费数据-" + data);
81 | } catch (InterruptedException e) {
82 | e.printStackTrace();
83 | }
84 | }
85 |
86 | }
87 |
88 |
89 |
--------------------------------------------------------------------------------
/javabase/datastructure/src/main/java/cn/tommyyang/string/StringTest.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.string;
2 |
3 | /**
4 | * @Author : TommyYang
5 | * @Time : 2019-06-04 11:12
6 | * @Software: IntelliJ IDEA
7 | * @File : StringTest.java
8 | */
9 | public class StringTest {
10 |
11 | public static void main(String[] args) {
12 | String a = "fsff";
13 | a.replace('s', '_');
14 |
15 | String b = new String("fsff");
16 | b.replace('s', '_');
17 |
18 | StringBuilder sb = new StringBuilder("fsff");
19 | sb.replace(1, 2, "_").toString().replace('_', 's');
20 | System.out.println(a);
21 | System.out.println(b);
22 | System.out.println(sb.toString());
23 | //通过以上例子发现 String 是不可变类, StringBuilder 是可变类
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/javabase/exception.md:
--------------------------------------------------------------------------------
1 | # 异常介绍
2 | 异常就是有异于常态,和正常情况不一样,有错误出现。在java中,阻止当前方法或作用域的情况,称之为异常。
3 |
4 | ## 异常分类
5 | 
6 |
7 | ## Exception具体实现
8 | 在系统开发中,平时经常需要使用的两种异常,一种是需要检查(checked)的,一种是不需要检查(unchecked)的。
9 | 那为什么需要两种异常呢?
10 | - 用来区分告警的优先级。系统异常优先级高,因为说明系统服务、代码存在问题。
11 | - 业务异常,是已知的,因为其他客观因素导致的,比如用户输入的身份证格式有问题、用户购买商品时金额不足等。
12 | - 系统异常,是未知的,不知道啥时候会发生,如果发生了说明系统本身或者系统上下游存在问题,需要立马告警出来,让相关开发者感知到;以便发现问题和后续优化问题。比如:系统上下游服务抖动、请求超时、请求参数存在问题等。
13 | - 使代码更清洁,该处理(checked)的异常内部处理掉,无法处理(unchecked)的异常告警出来。
14 |
15 | 往往对于开发者来说,比较难区分,何为系统系统,何为业务异常。其中系统异常是unchecked的,业务异常是checked。
16 |
17 | ### RuntimeException
18 | `RuntimeException`是在Java虚拟机的正常操作期间可以抛出的那些异常的超类,是Exception的子类,是Exception中unchecked子类的超类。
19 | 比如系统上下游抖动、请求超时等,是允许在系统运行期间抛出的,所以该类异常应该继承自`RuntimeException`;且无需检查(unchecked)。
20 | 所以系统异常应该继承自`RuntimeException`。
21 |
22 | 开发时具体实现:
23 |
24 | ```java
25 |
26 | /**
27 | * @Author : TommyYang
28 | * @Time : 2021-03-27 12:40
29 | * @Software: IntelliJ IDEA
30 | * @File : SystemException.java
31 | */
32 | public class SystemException extends RuntimeException {
33 |
34 | private String code;
35 |
36 | public SystemException(String code) {
37 | this.code = code;
38 | }
39 |
40 | public SystemException(String message, String code) {
41 | super(message);
42 | this.code = code;
43 | }
44 |
45 | @Override
46 | public String toString() {
47 | return "SystemException{" +
48 | "code='" + code + '\'' +
49 | '}';
50 | }
51 |
52 | }
53 |
54 | ```
55 |
56 | ### Exception
57 | 异常类和任何不是RuntimeException的子类的子类都是检查异常。 检查的异常需要在方法或构造函数的throws子句中声明,如果它们可以通过执行方法或构造函数抛出,并在方法或构造函数边界之外传播。
58 | 比如用户输入的身份证格式有问题、用户购买商品时金额不足等,这些是在开发系统的时候,就会已经的会出现这样的问题,这类异常是应该内部处理(checked)掉,而不应该告警出来。
59 | 所以业务异常应该继承自`Exception`,且需要检查(checked)。
60 |
61 | 开发时具体实现:
62 |
63 | ```java
64 |
65 | /**
66 | * @Author : TommyYang
67 | * @Time : 2021-03-27 12:40
68 | * @Software: IntelliJ IDEA
69 | * @File : BusinessException.java
70 | */
71 | public class BusinessException extends Exception {
72 |
73 | private String code;
74 |
75 | public BusinessException(String code) {
76 | this.code = code;
77 | }
78 |
79 | public BusinessException(String message, String code) {
80 | super(message);
81 | this.code = code;
82 | }
83 |
84 | @Override
85 | public String toString() {
86 | return "BusinessException{" +
87 | "code='" + code + '\'' +
88 | '}';
89 | }
90 | }
91 |
92 | ```
93 |
94 | ### 测试
95 |
96 | ```java
97 |
98 | /**
99 | * @Author : TommyYang
100 | * @Time : 2021-03-27 13:19
101 | * @Software: IntelliJ IDEA
102 | * @File : ExceptionTest.java
103 | */
104 | public class ExceptionTest {
105 |
106 | /**
107 | * 测试checked异常
108 | */
109 | @Test
110 | public void testException() {
111 | try {
112 | throwsBusinessException();
113 | } catch (BusinessException e) {
114 | System.out.println("这是一个业务异常,内部处理掉" + e.toString());
115 | }
116 | }
117 |
118 | /**
119 | * 测试unchecked异常
120 | */
121 | @Test
122 | public void testRuntimeException() {
123 | throwsSystemException();
124 | }
125 |
126 | /**
127 | * 抛出业务异常(checked)
128 | * 所以需要throw出去,让外部调用方感知到,这是一个checked的异常,是已经问题
129 | */
130 | private void throwsBusinessException() throws BusinessException {
131 | throw new BusinessException("403");
132 | }
133 |
134 | /**
135 | * 抛出系统异常(unchecked)
136 | */
137 | private void throwsSystemException() {
138 | throw new SystemException("400");
139 | }
140 |
141 | }
142 |
143 | ```
144 |
145 | ## Error介绍
146 | `Error`表示严重的问题,合理的应用程序不应该试图捕获。 大多数这样的错误是异常情况。 ThreadDeath错误虽然是“正常”的条件,但也是Error一个子类,因为大多数应用程序不应该试图抓住它。
147 |
148 | `Error`是由虚拟机生成并抛出,大多数错误与代码开发者所执行的操作无关。
149 | 常见的Error,比如Java虚拟机运行错误(VirtualMachineError);当JVM执行操作所需的内存资源不够时,将出现OutOfMemoryError;当这些异常发生时,JVM一般会选择线程终止。
150 | 还有部分Error是发生在虚拟机试图执行应用时,比如类定义错误(NoClassDefFoundError)、链接错误(LinkageError);这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。
151 | 对于合理设计的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。
152 | 在Java中,错误通常是使用Error的子类描述。
153 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/javabase/img/exception_category.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/javabase/img/exception_category.png
--------------------------------------------------------------------------------
/javabase/java8/README.md:
--------------------------------------------------------------------------------
1 | # Java8
2 | 分享 Java8 的新特性。
3 |
4 | ## 行为参数化(函数式接口)
5 |
6 | 1. 筛选某种颜色的苹果
7 | 2. 筛选重量大于某个值的苹果
8 |
9 | **Java8 之前的代码**
10 |
11 | ```java
12 |
13 | public class Apple {
14 |
15 | public static List filterApplesByColor(List inventory, String color) {
16 | List result = new ArrayList();
17 | for (Apple apple: inventory){
18 | if ( apple.getColor().equals(color) ) {
19 | result.add(apple);
20 | }
21 | }
22 | return result;
23 | }
24 |
25 | public static List filterApplesByWeight(List inventory, int weight) {
26 | List result = new ArrayList();
27 | for (Apple apple: inventory){
28 | if ( apple.getWeight() > weight ){
29 | result.add(apple);
30 | }
31 | }
32 | return result;
33 | }
34 | }
35 |
36 | ```
37 |
38 | **Java8 的代码简化**
39 |
40 | ```java
41 |
42 | @FunctionalInterface
43 | public interface ApplePredicate{
44 | boolean test (Apple apple);
45 | }
46 |
47 | public class ProgressDemo {
48 |
49 | public static List processApple(List appleList, ApplePredicate p) {
50 | List res = new ArrayList<>();
51 | for (Apple apple : appleList) {
52 | if (p.test(apple)) {
53 | res.add(apple);
54 | }
55 | }
56 | return res;
57 | }
58 |
59 | }
60 |
61 |
62 | ```
63 |
64 | ## Stream API
65 |
66 | 1. stream()
67 |
68 | 2. parallelStream()
69 |
70 | 非线程安全的;
71 | 默认线程池的数量就是处理器的数量,特殊场景下可以使用系统属性:
72 | -Djava.util.concurrent.ForkJoinPool.common.parallelism={N} 调整
73 |
74 | ## Lambada 表达式(链式编程)
75 |
76 | `基本语法`
77 |
78 | 1. (parameters) -> expression
79 | 2. (parameters) -> { statements; }
80 |
81 | ## 默认方法
82 | 实现有 default 方法的接口, 可以重写 default 方法,不重写则默认使用 interface 中的默认方法。
83 | 接口有默认方法之后,个人觉得接口和抽象类之间的区别更小了。
84 |
85 | ```java
86 |
87 | public interface DefaultInterface {
88 |
89 | void test();
90 |
91 | default String getName() {
92 | return "default";
93 | }
94 | }
95 |
96 | ```
--------------------------------------------------------------------------------
/javabase/java8/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | javainterview
7 | cn.tommyyang
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | javabase
13 |
14 |
15 |
16 |
17 | org.apache.maven.plugins
18 | maven-compiler-plugin
19 |
20 | 1.8
21 | 1.8
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/javabase/java8/src/main/java/cn/tommyyang/functioninterface/ApplePredicate.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.functioninterface;
2 |
3 | import cn.tommyyang.model.Apple;
4 |
5 | /**
6 | * @Author : TommyYang
7 | * @Time : 2019-08-08 14:44
8 | * @Software: IntelliJ IDEA
9 | * @File : ApplePredicate.java
10 | */
11 |
12 | public interface ApplePredicate {
13 | boolean test (Apple apple);
14 | }
15 |
--------------------------------------------------------------------------------
/javabase/java8/src/main/java/cn/tommyyang/functioninterface/DefaultInterface.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.functioninterface;
2 |
3 | /**
4 | * @Author : TommyYang
5 | * @Time : 2019-08-08 16:16
6 | * @Software: IntelliJ IDEA
7 | * @File : DefaultInterface.java
8 | */
9 | public interface DefaultInterface {
10 |
11 | void test();
12 |
13 | default String getName() {
14 | return "default";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/javabase/java8/src/main/java/cn/tommyyang/functioninterface/Demo.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.functioninterface;
2 |
3 | /**
4 | * @Author : TommyYang
5 | * @Time : 2019-08-08 16:17
6 | * @Software: IntelliJ IDEA
7 | * @File : Demo.java
8 | */
9 | public class Demo implements DefaultInterface {
10 | @Override
11 | public void test() {
12 | System.out.println("test");
13 | }
14 |
15 | // @Override
16 | // public String getName() {
17 | // return "demo";
18 | // }
19 | }
20 |
--------------------------------------------------------------------------------
/javabase/java8/src/main/java/cn/tommyyang/functioninterface/Predicate.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.functioninterface;
2 |
3 | /**
4 | * @Author : TommyYang
5 | * @Time : 2019-08-08 15:05
6 | * @Software: IntelliJ IDEA
7 | * @File : Predicate.java
8 | */
9 |
10 | @FunctionalInterface
11 | public interface Predicate {
12 |
13 | boolean test(T t);
14 |
15 | default Predicate or(Predicate super T> other) {
16 | return t -> test(t) || other.test(t);
17 | }
18 |
19 | default Predicate and(Predicate super T> other) {
20 | return t -> test(t) && other.test(t);
21 | }
22 |
23 | default Predicate negate() {
24 | return t -> !test(t);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/javabase/java8/src/main/java/cn/tommyyang/model/Apple.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.model;
2 |
3 | /**
4 | * @Author : TommyYang
5 | * @Time : 2019-08-08 14:44
6 | * @Software: IntelliJ IDEA
7 | * @File : Apple.java
8 | */
9 | public class Apple {
10 |
11 | private String color;
12 | private int weight;
13 |
14 | public Apple(String color, int weight) {
15 | this.color = color;
16 | this.weight = weight;
17 | }
18 |
19 | public String getColor() {
20 | return color;
21 | }
22 |
23 | public int getWeight() {
24 | return weight;
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | return "Apple{" +
30 | "color='" + color + '\'' +
31 | ", weight=" + weight +
32 | '}';
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/javabase/java8/src/main/java/cn/tommyyang/model/Fruit.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.model;
2 |
3 | import cn.tommyyang.functioninterface.Predicate;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * @Author : TommyYang
10 | * @Time : 2019-08-08 15:32
11 | * @Software: IntelliJ IDEA
12 | * @File : Fruit.java
13 | */
14 |
15 | public class Fruit {
16 |
17 | public List process(List ts, Predicate p) {
18 | List res = new ArrayList<>();
19 | for (T t : ts) {
20 | if (p.test(t)) {
21 | res.add(t);
22 | }
23 | }
24 | return res;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/javabase/java8/src/main/java/cn/tommyyang/model/Pear.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.model;
2 |
3 | /**
4 | * @Author : TommyYang
5 | * @Time : 2019-08-08 15:28
6 | * @Software: IntelliJ IDEA
7 | * @File : Pear.java
8 | */
9 | public class Pear {
10 |
11 | private String color;
12 | private int weight;
13 |
14 | public Pear(String color, int weight) {
15 | this.color = color;
16 | this.weight = weight;
17 | }
18 |
19 | public String getColor() {
20 | return color;
21 | }
22 |
23 | public int getWeight() {
24 | return weight;
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | return "Pear{" +
30 | "color='" + color + '\'' +
31 | ", weight=" + weight +
32 | '}';
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/javabase/java8/src/main/java/cn/tommyyang/streamapi/CountService.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.streamapi;
2 |
3 | import java.util.concurrent.atomic.AtomicLong;
4 |
5 | /**
6 | * @Author : TommyYang
7 | * @Time : 2019-08-06 16:58
8 | * @Software: IntelliJ IDEA
9 | * @File : CountService.java
10 | */
11 | public class CountService {
12 |
13 | private long a;
14 | private AtomicLong atomicLong = new AtomicLong(0);
15 |
16 | public void count(int b) {
17 | this.a = a + b;
18 | }
19 |
20 | public void atomicCount(int b) {
21 | this.atomicLong.addAndGet(b);
22 | }
23 |
24 | public long getA() {
25 | return a;
26 | }
27 |
28 | public long getCount() {
29 | return this.atomicLong.get();
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/javabase/java8/src/main/java/cn/tommyyang/streamapi/StreamAPI.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.streamapi;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.stream.Stream;
6 |
7 | /**
8 | * @Author : TommyYang
9 | * @Time : 2019-08-06 16:56
10 | * @Software: IntelliJ IDEA
11 | * @File : StreamAPI.java
12 | */
13 | public class StreamAPI {
14 |
15 | private static List addItems;
16 | private static Stream stream;
17 | private static Stream parallelStream;
18 |
19 | static {
20 | addItems = new ArrayList<>(10);
21 | for (int i = 1; i <= 10; i++) {
22 | addItems.add(i);
23 | }
24 | stream = addItems.stream();
25 | parallelStream = addItems.parallelStream();
26 | }
27 |
28 | public static void main(String[] args) {
29 | // testDisplay();
30 | // testAdd();
31 | streamDisplay();
32 | }
33 |
34 | public static void testAdd() {
35 | long t1 = System.currentTimeMillis();
36 | streamAdd();
37 | long t2 = System.currentTimeMillis();
38 | parallelStreamAdd();
39 | long t3 = System.currentTimeMillis();
40 | defaultAdd();
41 | long t4 = System.currentTimeMillis();
42 |
43 | System.out.println("streamAdd time used:" + (t2 - t1));
44 | System.out.println("parallelStreamAdd time used:" + (t3 - t2));
45 | System.out.println("defaultAdd time used:" + (t4 - t3));
46 | }
47 |
48 | public static void testDisplay() {
49 | long t1 = System.currentTimeMillis();
50 | streamDisplay();
51 | long t2 = System.currentTimeMillis();
52 | parallelStreamDisplay();
53 | long t3 = System.currentTimeMillis();
54 | defaultDisplay();
55 | long t4 = System.currentTimeMillis();
56 |
57 | System.out.println("stream time used:" + (t2 - t1));
58 | System.out.println("parallelStream time used:" + (t3 - t2));
59 | System.out.println("default time used:" + (t4 - t3));
60 | }
61 |
62 | public static void streamAdd() {
63 | CountService countService = new CountService();
64 | stream.forEach(countService::atomicCount);
65 |
66 | System.out.println(countService.getCount());
67 | }
68 |
69 | public static void parallelStreamAdd() {
70 | CountService countService = new CountService();
71 | parallelStream.forEach(countService::atomicCount);
72 |
73 | System.out.println(countService.getCount());
74 | }
75 |
76 | public static void defaultAdd() {
77 | CountService countService = new CountService();
78 | for (int i : addItems) {
79 | countService.atomicCount(i);
80 | }
81 |
82 | System.out.println(countService.getCount());
83 | }
84 |
85 | public static void streamDisplay() {
86 | // stream.forEach(System.out::println);
87 | // stream.forEach(item -> {
88 | // try {
89 | // Thread.sleep(500);
90 | // } catch (InterruptedException e) {
91 | // e.printStackTrace();
92 | // }
93 | // System.out.println(item);
94 | // });
95 |
96 | addItems.forEach(System.out::println);
97 |
98 | System.out.println("stream display end ------");
99 | }
100 |
101 | public static void parallelStreamDisplay() {
102 | parallelStream.forEach(item -> {
103 | try {
104 | Thread.sleep(500);
105 | } catch (InterruptedException e) {
106 | e.printStackTrace();
107 | }
108 | System.out.println(item);
109 | });
110 |
111 | System.out.println("parallel stream display end ------");
112 | }
113 |
114 | public static void defaultDisplay() {
115 | for (int i : addItems) {
116 | try {
117 | Thread.sleep(500);
118 | } catch (InterruptedException e) {
119 | e.printStackTrace();
120 | }
121 | System.out.println(i);
122 | }
123 |
124 | System.out.println("end--------");
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/javabase/keywords/README.md:
--------------------------------------------------------------------------------
1 | # 关键字篇
2 | 1. [transient](transient.md)
3 | 2. [volatile](volatile.md)
4 |
5 |
--------------------------------------------------------------------------------
/javabase/keywords/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | javainterview
7 | cn.tommyyang
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | keywords
13 |
14 |
15 |
--------------------------------------------------------------------------------
/javabase/keywords/res/transient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/javabase/keywords/res/transient.png
--------------------------------------------------------------------------------
/javabase/keywords/res/transienttest.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/javabase/keywords/res/transienttest.txt
--------------------------------------------------------------------------------
/javabase/keywords/src/main/java/transientkey/TransientTest.java:
--------------------------------------------------------------------------------
1 | package transientkey;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by TommyYang on 2018/3/19.
7 | */
8 | public class TransientTest implements Serializable{
9 |
10 | private static final long serialVersionUID = -2670851086407643335L;
11 |
12 | private transient int a = 1; //不会被序列化(持久化),将该对象保存到磁盘中的时候,该属性不会被保存
13 |
14 | private int b = 8;
15 |
16 | public int getA() {
17 | return a;
18 | }
19 |
20 | public int getB() {
21 | return b;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/javabase/keywords/src/main/java/volatilekey/ordering/AThread.java:
--------------------------------------------------------------------------------
1 | package volatilekey.ordering;
2 |
3 | /**
4 | * @author TommyYang on 2019/1/30
5 | */
6 | public class AThread implements Runnable {
7 |
8 | public void run() {
9 | // Model.b = 4;
10 | // Model.c = 5;
11 | // Model.d = 6;
12 |
13 | Model.a = 11;
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/javabase/keywords/src/main/java/volatilekey/ordering/BThread.java:
--------------------------------------------------------------------------------
1 | package volatilekey.ordering;
2 |
3 | /**
4 | * @author TommyYang on 2019/1/30
5 | */
6 | public class BThread implements Runnable {
7 |
8 | public void run() {
9 |
10 | System.out.println(Model.a);
11 | // System.out.println(Model.b);
12 | // System.out.println(Model.c);
13 | // System.out.println(Model.d);
14 |
15 |
16 |
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/javabase/keywords/src/main/java/volatilekey/ordering/Model.java:
--------------------------------------------------------------------------------
1 | package volatilekey.ordering;
2 |
3 | /**
4 | * @author TommyYang on 2019/1/30
5 | */
6 | public class Model {
7 |
8 | public volatile static int a;
9 | public static int b = 1;
10 | public static int c = 2;
11 | public static int d = 3;
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/javabase/keywords/src/main/java/volatilekey/ordering/RunTest.java:
--------------------------------------------------------------------------------
1 | package volatilekey.ordering;
2 |
3 | /**
4 | * @author TommyYang on 2019/1/30
5 | */
6 | public class RunTest {
7 |
8 | public static void main(String[] args) throws InterruptedException {
9 |
10 | for (int i = 0; i < 10000; i++){
11 | Model.a = 10;
12 | Thread at = new Thread(new AThread());
13 | Thread bt = new Thread(new BThread());
14 |
15 |
16 | at.start();
17 | bt.start();
18 |
19 | bt.join();
20 | at.join();
21 | }
22 |
23 |
24 |
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/javabase/keywords/src/main/java/volatilekey/unsafe/Counter.java:
--------------------------------------------------------------------------------
1 | package volatilekey.unsafe;
2 |
3 | import sun.misc.Unsafe;
4 |
5 | /**
6 | * @author TommyYang on 2019/1/28
7 | */
8 | public class Counter{
9 |
10 | private final Long serialVersionUID = 0L;
11 |
12 | private static final Unsafe unsafe = OwnUnSafe.getUnSafe();
13 | private static final long valueOffset;
14 |
15 | static {
16 | try {
17 | valueOffset = unsafe.objectFieldOffset
18 | (Counter.class.getDeclaredField("value"));
19 | } catch (Exception ex) { throw new Error(ex); }
20 | }
21 |
22 | private volatile int value;
23 |
24 | public Counter(int value) {
25 | this.value = value;
26 | }
27 |
28 | public final void increment(){
29 | for(;;){
30 | int current = getValue();
31 | int next = current + 1;
32 | if(compareAndSet(current, next)){
33 | return;
34 | }
35 | }
36 | }
37 |
38 | public final void decrement(){
39 | for(;;){
40 | int current = getValue();
41 | int next = current - 1;
42 | if(compareAndSet(current, next)){
43 | return;
44 | }
45 | }
46 | }
47 |
48 | public final int getValue() {
49 | return this.value;
50 | }
51 |
52 | public final boolean compareAndSet(int expect, int update) {
53 | return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/javabase/keywords/src/main/java/volatilekey/unsafe/OwnUnSafe.java:
--------------------------------------------------------------------------------
1 | package volatilekey.unsafe;
2 |
3 | import sun.misc.Unsafe;
4 |
5 | import java.lang.reflect.Field;
6 |
7 | /**
8 | * @author TommyYang on 2019/1/29
9 | */
10 | public class OwnUnSafe {
11 |
12 | public static Unsafe getUnSafe() {
13 | try {
14 | Class unsafeClass = Class.forName("sun.misc.Unsafe");
15 | Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");
16 | boolean orignialAccessible = theUnsafeField.isAccessible();
17 | theUnsafeField.setAccessible(true);
18 | Object unsafeInstance = theUnsafeField.get(null); //unsafeInstance就是Unsafe的实例
19 | theUnsafeField.setAccessible(orignialAccessible);
20 | return (Unsafe)unsafeInstance;
21 | } catch (IllegalAccessException e) {
22 | e.printStackTrace();
23 | } catch (NoSuchFieldException e) {
24 | e.printStackTrace();
25 | } catch (ClassNotFoundException e) {
26 | e.printStackTrace();
27 | }
28 |
29 | return null;
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/javabase/keywords/src/main/java/volatilekey/unsafe/Runtest.java:
--------------------------------------------------------------------------------
1 | package volatilekey.unsafe;
2 |
3 | /**
4 | * Created by TommyYang on 2018/3/19.
5 | */
6 | public class Runtest {
7 |
8 | public static void main(String[] args) throws InterruptedException {
9 | ThreadCommunicate th = new ThreadCommunicate();
10 |
11 | Thread incrementTask = new Thread(th.new IncrementTask());
12 | Thread decrementTask = new Thread(th.new DecrementTask());
13 | incrementTask.start();
14 | decrementTask.start();
15 | incrementTask.join(); //让主线程等待子线程结束之后才能继续运行。
16 | decrementTask.join();
17 |
18 |
19 | System.out.println(th.getCounter().getValue());
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/javabase/keywords/src/main/java/volatilekey/unsafe/ThreadCommunicate.java:
--------------------------------------------------------------------------------
1 | package volatilekey.unsafe;
2 |
3 | /**
4 | * Created by TommyYang on 2018/3/19.
5 | */
6 | public class ThreadCommunicate {
7 |
8 |
9 | Counter counter = new Counter(0);
10 |
11 | public Counter getCounter() {
12 | return counter;
13 | }
14 |
15 | class IncrementTask implements Runnable {
16 |
17 | public void run() {
18 | for(int i = 0; i < 100000; i++){
19 | counter.increment();
20 | }
21 |
22 | }
23 | }
24 |
25 | class DecrementTask implements Runnable {
26 |
27 | public void run() {
28 | for(int i = 0; i < 100000; i++){
29 | counter.decrement();
30 | }
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/javabase/keywords/src/main/java/volatilekey/visibility/RunTest.java:
--------------------------------------------------------------------------------
1 | package volatilekey.visibility;
2 |
3 | /**
4 | * @author TommyYang on 2019/1/29
5 | */
6 | public class RunTest extends Thread {
7 |
8 | //volatile保证线程的可见性
9 | //private volatile boolean isRunning = true;
10 | private boolean isRunning = true;
11 |
12 | public boolean isRunning() {
13 | return isRunning;
14 | }
15 |
16 | public void setRunning(boolean running) {
17 | isRunning = running;
18 | }
19 |
20 | public void run(){
21 |
22 | while (isRunning()){
23 | }
24 | System.out.println("not running");
25 | }
26 |
27 | public static void main(String[] args) throws InterruptedException {
28 | RunTest voatileTest = new RunTest();
29 | voatileTest.start();
30 |
31 | Thread.sleep(1000);
32 |
33 | voatileTest.setRunning(false);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/javabase/keywords/transient.md:
--------------------------------------------------------------------------------
1 | # 关键字-transient
2 |
3 | ## 介绍
4 | 词义:短暂的
5 |
6 | 首先说说“序列化”,把一个对象的表示转化为字节流的过程称为串行化(也称为序列化,serialization),从字节流中把对象重建出来称为反串行化(也称为为反序列化,deserialization)。transient 为不应被串行化的数据提供了一个语言级的标记数据方法。
7 |
8 | ## 代码测试
9 | ```
10 |
11 | public class TransientTest implements Serializable{
12 |
13 | private static final long serialVersionUID = -2670851086407643335L;
14 |
15 | private transient int a = 1; //不会被序列化(持久化),将该对象保存到磁盘中的时候,该属性不会被保存
16 |
17 | private int b = 8;
18 |
19 | public int getA() {
20 | return a;
21 | }
22 |
23 | public int getB() {
24 | return b;
25 | }
26 | }
27 |
28 | //测试类
29 | public class RunTest {
30 |
31 | public static void main(String[] args) throws IOException, ClassNotFoundException {
32 | //write Serializable object to file
33 | TransientTest test = new TransientTest();
34 | FileOutputStream fileOutputStream = new FileOutputStream("KeyWords/res/transienttest.txt");
35 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
36 | objectOutputStream.writeObject(test);
37 | objectOutputStream.flush();
38 | objectOutputStream.close();
39 |
40 | //get Serializable object from file
41 | ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("KeyWords/res/transienttest.txt"));
42 | TransientTest transientTest = (TransientTest) objectInputStream.readObject();
43 | System.out.println("a=" + transientTest.getA() + "\t" +"b=" + transientTest.getB());
44 | }
45 |
46 | }
47 |
48 | ```
49 |
50 | ## transienttest.txt文件内容
51 | [transienttest.txt](res/transienttest.txt)
52 |
53 |
54 | ## 结果
55 |
56 | 
57 |
--------------------------------------------------------------------------------
/javabase/keywords/volatile.md:
--------------------------------------------------------------------------------
1 | # 关键字-volatile
2 |
3 | ## 介绍
4 | 词义:易变的
5 |
6 | volatile也是变量修饰符,只能用来修饰变量。volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
7 |
8 | 在此解释一下Java的内存机制:
9 |
10 | Java使用一个主内存来保存变量当前值,而每个线程则有其独立的工作内存。线程访问变量的时候会将变量的值拷贝到自己的工作内存中,这样,当线程对自己工作内存中的变量进行操作之后,就造成了工作内存中的变量拷贝的值与主内存中的变量值不同。Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。
11 |
12 | 而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
13 |
14 | 对于volatile类型的变量,系统每次用到他的时候都是直接从对应的内存当中提取,而不会利用cache当中的原有数值,以适应它的未知何时会发生的变化,系统对这种变量的处理不会做优化——显然也是因为它的数值随时都可能变化的情况。
--------------------------------------------------------------------------------
/javabase/stringbuilderandstringbuffer.md:
--------------------------------------------------------------------------------
1 | # StringBuffer 和 StringBuilder
2 |
3 | ## 介绍
4 | 大多数情况下, StringBuffer 的速度要比 String 快; StringBuilder 要比StringBuffer快;StringBuffer 和 StringBuilder 都是 AbstractStringBuilder 的子类,区别在于StringBuffer 的方法大部分都有 synchronized 修饰。
5 |
6 | ## 源码解析
7 |
8 | ### AbstractStringBuilder
9 |
10 | #### 变量及构造方法
11 |
12 | ``` java
13 |
14 | /**
15 | * 用来存储字符的数组
16 | * The value is used for character storage.
17 | */
18 | char[] value;
19 |
20 | /**
21 | * 字符个数
22 | * The count is the number of characters used.
23 | */
24 | int count;
25 |
26 | /**
27 | * This no-arg constructor is necessary for serialization of subclasses.
28 | */
29 | AbstractStringBuilder() {
30 | }
31 |
32 | /**
33 | * 在构造方法中指定字符数组的长度
34 | * Creates an AbstractStringBuilder of the specified capacity.
35 | */
36 | AbstractStringBuilder(int capacity) {
37 | value = new char[capacity];
38 | }
39 |
40 | ```
41 |
42 |
43 | #### 扩容
44 |
45 | ``` java
46 | public void ensureCapacity(int minimumCapacity) {
47 | if (minimumCapacity > 0)
48 | ensureCapacityInternal(minimumCapacity);
49 | }
50 |
51 | private void ensureCapacityInternal(int minimumCapacity) {
52 | // overflow-conscious code
53 | if (minimumCapacity - value.length > 0) {
54 | value = Arrays.copyOf(value,
55 | newCapacity(minimumCapacity));
56 | }
57 | }
58 |
59 | private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
60 |
61 | private int newCapacity(int minCapacity) {
62 | // overflow-conscious code
63 | int newCapacity = (value.length << 1) + 2;
64 | if (newCapacity - minCapacity < 0) {
65 | newCapacity = minCapacity;
66 | }
67 | return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
68 | ? hugeCapacity(minCapacity)
69 | : newCapacity;
70 | }
71 |
72 | private int hugeCapacity(int minCapacity) {
73 | if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
74 | throw new OutOfMemoryError();
75 | }
76 | return (minCapacity > MAX_ARRAY_SIZE)
77 | ? minCapacity : MAX_ARRAY_SIZE;
78 | }
79 | ```
80 |
81 | 扩容的方法最终由 `newCapacity()` 实现的,首先将容量左移一位(即扩大2倍)同时加2,如果此时任小于指定的容量,那么就将容量设置为 `minimumCapacity` 。然后判断是否溢出,通过 `hugeCapacity` 实现,如果溢出了(长度大于 `Integer.MAX_VALUE` ),则抛错( `OutOfMemoryError` );否则根据 `minCapacity` 和 `Integer.MAX_VALUE - 8` 的大小比较确定数组容量为 `max(minCapacity, Integer.MAX_VALUE - 8)`。最后将 `value` 值进行拷贝,这一步显然是最耗时的操作。
82 |
83 | #### append() 方法
84 |
85 | ``` java
86 | public AbstractStringBuilder append(String str) {
87 | if (str == null)
88 | return appendNull();
89 | int len = str.length();
90 | ensureCapacityInternal(count + len);
91 | str.getChars(0, len, value, count);
92 | count += len;
93 | return this;
94 | }
95 | ```
96 | `append()` 是最常用的方法,它有很多形式的重载。上面是最常用的一种,用于追加字符串。如果 `str` 是 `null` ,则直接调用
97 | `appendNull()` 方法。这个方法就是直接追加 `'n'` 、 `'u'` 、`'l'`、`'l'` 这几个字符,方法如下:
98 |
99 | ``` java
100 |
101 | private AbstractStringBuilder appendNull() {
102 | int c = count;
103 | ensureCapacityInternal(c + 4);
104 | final char[] value = this.value;
105 | value[c++] = 'n';
106 | value[c++] = 'u';
107 | value[c++] = 'l';
108 | value[c++] = 'l';
109 | count = c;
110 | return this;
111 | }
112 |
113 | ```
114 |
115 | 如果不是` null `,则首先需要判断数组容量是否足够,不够则需要扩容(扩容则是调用上述分析的扩容方法);
116 | 然后调用 `String` 的 `getChars()` 方法将 `str` 追加到 `value` 末尾;
117 | 最后返回对象本身,所以 `append()` 可以连续调用(就是一种类似于链式编程)。
118 |
119 |
120 | ### 思考
121 | - 为什么每次扩容是扩容为原来的两倍?
122 | 个人觉得是为了避免经常扩容带来的成本消耗。
123 | - 为什么会加2呢?
124 | 个人也没想出什么好的解释,觉得可能是因为 `Java` 开发者认为我们在 `append` 数据的时候,中间经常会加一个分隔符,恰好这个分隔符在 `Java` 中正好占用两个字节。也不知道分析的对不对,有其他意见的大佬们可以在 [issue](https://github.com/joyang1/JavaInterview/issues/2)
125 | 中进行讨论。
126 |
127 |
128 | ### StringBuilder 与 StringBuffer 方法对比
129 |
130 | 通过查看源码分析发现两者都继承至 `AbstractStringBuilder` 。 而 `StringBuffer` 之所以是线程安全的,是因为重写 `AbstractStringBuilder` 的方法的时候在前面加上了 `synchronzied` 修饰这些方法;而 `StringBuilder` 重写的时候只是直接调用父类的方法,没有做其他的操作。
131 |
132 | 其实通过阅读源码发现 `StringBuilder` 和 `StringBuffer` 之间的关系,类似于 `HashMap` 和 `HashTable` 之间的关系。
133 |
134 |
135 |
--------------------------------------------------------------------------------
/jvm/README.md:
--------------------------------------------------------------------------------
1 | # 深入浅出 JVM
2 | 该篇主要是**深入理解 Java 虚拟机-第二版**的读书笔记总结。
3 |
4 | >**目录**
5 |
6 | - [运行时数据区域](#运行时数据区域)
7 | - [垃圾回收算法](#垃圾回收算法)
8 | - [垃圾收集器](#垃圾收集器)
9 |
10 | ## 运行时数据区域
11 | - 线程私有区域
12 | - 程序计数器
13 | - Java 虚拟机栈
14 | - 本地方法栈
15 | - 线程共享区域
16 | - Java 堆
17 | - 方法区
18 | - 运行时常量池(属于方法区的一部分)
19 |
20 | ---
21 |
22 | ### 线程私有区域
23 | #### 程序计数器
24 | 程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计算器来完成。
25 |
26 | 由于 Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。故为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,所以这块内存区域是"线程私有"的区域。
27 |
28 | #### Java 虚拟机栈
29 | Java 虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是 Java 方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
30 |
31 | #### 本地方法栈
32 | 本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机栈执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。
33 |
34 | ---
35 |
36 | ### 线程共享区域
37 | #### Java 堆
38 | 对于大多数应用来说,Java 堆(Java Heap)是 Java 虚拟机所管理的内存中最大的一块。Java 堆是被**所有线程共享**的一块内存区域,在虚拟机启动是创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在 Java 虚拟机规范中的描述是:所有对象的实例以及数组都要在堆上分配,但是随着 JIT 编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化发生,所有对象都分配在堆上也渐渐变得没那么"绝对"了。
39 |
40 | #### 方法区(非堆)
41 | 方法区(Method Area)与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然 Java 虚拟机规范把 Java 方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 **Non Heap**(非堆),目的应该是与 Java 堆区分开来。
42 |
43 | 方法区也被开发者成为"永久代"(Permanent Generation)。
44 |
45 | #### 运行时常量池(属于方法区的一部分)
46 | Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
47 |
48 |
49 | ---
50 |
51 | ## 垃圾回收算法
52 | ### 标记-清除(Mark-Sweep)算法
53 | 如同名字一样,算法分为"标记"和"清除"两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象,它的标记过程其实在前一节讲述对象标记判定时已经介绍过了。之所以说它是最基础的算法,是因为后续的收集算法都是基于这种思路并对其不足进行改进而得到的。
54 |
55 | 它的主要不足有两个:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
56 |
57 |
58 | ### 复制算法
59 | 为了解决效率问题,复制(Copying)算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样就是每次只对其中一块内存进行回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
60 |
61 | 这种算法的代价是将内存缩小为了原来的一半,代价很大。这种算法也在特殊场景中会有很大用处,比如回收新生代的时候,IBM 公司的专门研究表明,新生代的对象 98% 是"朝生夕灭"的,所以不需要按照 1:1 的比例来划分内存区域,而是将内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 空间和其中一块 Survivor 空间。当回收时,将 Eden 空间和 Survivor 空间中还存活着的对象一次性地复制到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才使用过的 Survivor 空间。这里肯定有一个具体空间分配比例,HotSpot 虚拟机默认 Eden:Survivor 为 8:1,也就是每次新生代中可用内存为整个新生代的 90%(80%+10%),只有 10% 的内存会被"浪费"。当然,98% 的对象可回收只是一般场景下的数据,JVM 没有办法保证每次回收都只有不多于 10% 的对象存活,当 Survivor 空间不够用时,需要依赖其它内存(这里指老年代)进行分配担保(Handle Promotion)。
62 |
63 | 内存的分配担保就好比我们现在使用支付宝里面的花呗,如果我们信誉很好,在 98% 的情况下都能按时偿还,于是支付宝会默认我们会在下一月也能按时按量的偿还我们的预支,只需要有一个担保人能保证如果我下次不能还款时,可以帮助你还钱,那支付宝就认为我们预支花呗是没有风险的。内存的分配担保也一样,如果另外一块 Survivor 空间没有足够空间存放上一次新生代收集下来的存活对象时,这些对象将直接通过分配担保机制进入老年代。具体怎么分配担保会在后续分析。
64 |
65 | ### 标记-整理算法
66 | 复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。更关键的是,如果不想浪费 50% 的空间,就需要有额外的空间进行分配担保,以应对使用的内存中所有对象都 100% 存活的极端情况,所以在老年代一般不能直接选用复制算法。
67 |
68 | 根据老年代存活时间较长的特点,有人提出了另一种"标记-整理"(Mark-Compact)的算法,标记过程仍然与"标记-清除"算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象向一端移动,然后直接清理掉边界以外的内存。
69 |
70 | ### 分代收集算法
71 | 这种算法没有什么新的思想,只是根据对象存活周期的不同将内存划分为几块。一般把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的算法。
72 |
73 | - 新生代:复制算法
74 |
75 | 因为在新生代中,每次垃圾回收时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需付出少量存活对象的复制成本就可以完成收集。
76 |
77 | - 老年代:标记-清理/标记-整理
78 |
79 | 因为老年代对象存活率高、没有额外空间对它进行分配担保。
80 |
81 | ## 垃圾收集器
82 | 该部分单独总结,参见[garbage_collectors](garbage_collectors.md)。
--------------------------------------------------------------------------------
/jvm/jvm_params.md:
--------------------------------------------------------------------------------
1 | # JVM 参数
2 | - 查看 JVM 使用什么垃圾回收器:java -XX:+PrintCommandLineFlags -version
3 |
4 | ``` properties
5 |
6 | -XX:InitialHeapSize=2147483648 -XX:MaxHeapSize=32210157568 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
7 | openjdk version "1.8.0_222"
8 | OpenJDK Runtime Environment (build 1.8.0_222-8u222-b10-1ubuntu1~16.04.1-b10)
9 | OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
10 |
11 | ```
12 |
--------------------------------------------------------------------------------
/lock/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | javainterview
7 | cn.tommyyang
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | lock
13 |
14 |
15 |
16 | cn.tommyyang
17 | keywords
18 | 1.0-SNAPSHOT
19 |
20 |
21 |
22 | org.redisson
23 | redisson
24 | 3.10.7
25 |
26 |
27 |
28 |
29 | org.apache.zookeeper
30 | zookeeper
31 | 3.4.14
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/lock/src/main/java/cn/tommyyang/demo/RunTest.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.demo;
2 |
3 | import cn.tommyyang.demo.lock.Consumer;
4 | import cn.tommyyang.demo.lock.Producer;
5 | import cn.tommyyang.demo.lock.ReentrantLockDemo;
6 | import cn.tommyyang.demo.lock.SynchronizedDemo;
7 | import volatilekey.unsafe.Counter;
8 |
9 | import java.util.concurrent.*;
10 | import java.util.concurrent.ExecutorService;
11 | import java.util.concurrent.Executors;
12 | import java.util.concurrent.locks.Condition;
13 | import java.util.concurrent.locks.ReentrantLock;
14 |
15 | /**
16 | * @author TommyYang on 2019/1/28
17 | */
18 | public class RunTest {
19 |
20 | public static void main(String[] args) {
21 |
22 | //runSynchronizedDemo();
23 |
24 | //runReenTrantLockDemo();
25 |
26 | //runCASDemo();
27 |
28 | runSynchronizedP_C_Demo();
29 |
30 | //runReentrantLockP_C_Demo();
31 | }
32 |
33 |
34 |
35 | public static void runSynchronizedP_C_Demo(){
36 | Producer pro = new Producer();
37 | Consumer con = new Consumer();
38 | Thread t1 = new Thread(pro);
39 | Thread t2 = new Thread(pro);
40 |
41 | Thread c1 = new Thread(con);
42 | Thread c2 = new Thread(con);
43 |
44 | t1.start();
45 | t2.start();
46 |
47 | c1.start();
48 | c2.start();
49 |
50 |
51 | }
52 |
53 | public static void runReentrantLockP_C_Demo(){
54 | ReentrantLock lock = new ReentrantLock();
55 | Condition cCondition = lock.newCondition();
56 | Condition pCondition = lock.newCondition();
57 | Producer pro = new Producer(lock, cCondition, pCondition);
58 | Thread t1 = new Thread(pro);
59 | Thread t2 = new Thread(pro);
60 |
61 | Consumer con = new Consumer(lock, cCondition, pCondition);
62 | Thread c1 = new Thread(con);
63 | Thread c2 = new Thread(con);
64 |
65 | t1.start();
66 | t2.start();
67 |
68 | c1.start();
69 | c2.start();
70 |
71 |
72 |
73 | }
74 |
75 | public static void runSynchronizedDemo(){
76 | final ExecutorService pool = Executors.newFixedThreadPool(10);
77 | for(int i = 0; i < 2; i++){
78 | pool.execute(new SynchronizedDemo());
79 | }
80 | pool.shutdown();
81 |
82 | while (true){
83 | if(pool.isTerminated()){
84 | System.out.println(SynchronizedDemo.common);
85 | break;
86 | }
87 | }
88 | }
89 |
90 | public static void runReenTrantLockDemo(){
91 | ReentrantLock lock = new ReentrantLock(true);
92 | ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
93 |
94 | reentrantLockDemo.newThread(lock, "tttt1");
95 | reentrantLockDemo.newThread(lock, "tttt2");
96 |
97 | reentrantLockDemo.newThread(lock, "tttt3");
98 | reentrantLockDemo.newThread(lock, "tttt4");
99 |
100 | }
101 |
102 | public static void runCASDemo(){
103 | final Counter counter = new Counter(0);
104 |
105 | new Thread(new Runnable() {
106 | public void run() {
107 | counter.compareAndSet(0, 1);
108 |
109 | System.out.println("sleep 1s");
110 | try {
111 | Thread.sleep(1000);
112 | } catch (InterruptedException e) {
113 | e.printStackTrace();
114 | }
115 | System.out.println("重置value为0");
116 | counter.compareAndSet(1, 0);
117 | }
118 | }).start();
119 |
120 | new Thread(new Runnable() {
121 | public void run() {
122 | System.out.println("等待中.....");
123 | counter.compareAndSet(0, 2);
124 | System.out.println(counter.getValue());
125 | }
126 | }).start();
127 |
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/lock/src/main/java/cn/tommyyang/demo/lock/Consumer.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.demo.lock;
2 |
3 | import java.util.concurrent.locks.Condition;
4 | import java.util.concurrent.locks.ReentrantLock;
5 |
6 | /**
7 | * @author TommyYang on 2019-04-06
8 | */
9 | public class Consumer implements Runnable {
10 |
11 | private ReentrantLock lock;
12 | private Condition cCondition;
13 | private Condition pCondition;
14 |
15 | public Consumer() {
16 | }
17 |
18 | public Consumer(ReentrantLock lock, Condition cCondition, Condition pCondition) {
19 | this.lock = lock;
20 | this.cCondition = cCondition;
21 | this.pCondition = pCondition;
22 | }
23 |
24 | public void consume1() throws InterruptedException {
25 | synchronized (Producer.data) {
26 | while (!Producer.flag){
27 | System.out.println("进入Consumer wait");
28 | Producer.data.wait();
29 | }
30 | this.consume();
31 | Producer.flag = false;
32 | Producer.data.notifyAll();
33 | }
34 |
35 | }
36 |
37 | public void consume2() throws InterruptedException {
38 | try {
39 | this.lock.lock();
40 | while (!Producer.flag){
41 | System.out.println("进入Consumer await");
42 | this.cCondition.await();
43 | }
44 | this.consume();
45 | Producer.flag = false;
46 | this.pCondition.signalAll();
47 | } finally {
48 | this.lock.unlock();
49 | }
50 |
51 |
52 |
53 | }
54 |
55 | public void consume(){
56 | System.out.println(String.format("thread id:%d, name:%s start to consume data",
57 | Thread.currentThread().getId(), Thread.currentThread().getName()));
58 | if (Producer.data.size() > 0) {
59 | System.out.println(String.format("consume value: %d", Producer.data.remove()));
60 | } else {
61 | System.out.println("no data");
62 | }
63 | }
64 |
65 | public void run() {
66 |
67 | for (; ; ) {
68 | try {
69 | this.consume1();
70 | //this.consume2();
71 | }catch (InterruptedException e) {
72 | e.printStackTrace();
73 | }
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/lock/src/main/java/cn/tommyyang/demo/lock/Producer.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.demo.lock;
2 |
3 | import java.util.*;
4 | import java.util.concurrent.locks.Condition;
5 | import java.util.concurrent.locks.ReentrantLock;
6 |
7 | /**
8 | * @author TommyYang on 2019-04-06
9 | */
10 | public class Producer implements Runnable {
11 |
12 | public static LinkedList data = new LinkedList();
13 | public static boolean flag = false;
14 |
15 | private ReentrantLock lock;
16 | private Condition cCondition;
17 | private Condition pCondition;
18 |
19 | public Producer() {
20 | }
21 |
22 | public Producer(ReentrantLock lock, Condition cCondition, Condition pCondition) {
23 | this.lock = lock;
24 | this.cCondition = cCondition;
25 | this.pCondition = pCondition;
26 | }
27 |
28 | public void produce() {
29 | System.out.println(String.format("thread id:%d, name:%s start to produce data",
30 | Thread.currentThread().getId(), Thread.currentThread().getName()));
31 | data.add(1);
32 | }
33 |
34 | public void produce1() throws InterruptedException {
35 | synchronized (data) {
36 | while (flag){
37 | System.out.println("进入Producer wait");
38 | data.wait();
39 | }
40 | this.produce();
41 | flag = true;
42 | data.notifyAll();
43 | }
44 |
45 | }
46 |
47 | public void produce2() throws InterruptedException {
48 | try {
49 | this.lock.lock();
50 | while (flag){
51 | System.out.println("进入Producer await");
52 | this.pCondition.await();
53 | }
54 | this.produce();
55 | flag = true;
56 | this.cCondition.signalAll();
57 | } finally {
58 | this.lock.unlock();
59 | }
60 |
61 | }
62 |
63 | public void run() {
64 | for (; ; ) {
65 | try {
66 | this.produce1();
67 | //this.produce2();
68 | } catch (InterruptedException e) {
69 | e.printStackTrace();
70 | }
71 |
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lock/src/main/java/cn/tommyyang/demo/lock/ReentrantLockDemo.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.demo.lock;
2 |
3 | import java.util.concurrent.locks.ReentrantLock;
4 |
5 | /**
6 | * @author TommyYang on 2019-03-21
7 | */
8 | public class ReentrantLockDemo {
9 |
10 | public void newThread(final ReentrantLock lock, final String name){
11 | new Thread(new Runnable() {
12 | public void run() {
13 | lock.lock();
14 | System.out.println(name + ":第一次进入lock");
15 | try {
16 | Thread.sleep(1000);
17 | System.out.println(name + ":再次进入lock");
18 | lock.lock();
19 | } catch (InterruptedException e) {
20 | e.printStackTrace();
21 | }finally {
22 | lock.unlock();
23 | System.out.println(name + ":第一次unlock");
24 | lock.unlock();
25 | System.out.println(name + ":第二次unlock");
26 | }
27 | }
28 | }, name).start();
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/lock/src/main/java/cn/tommyyang/demo/lock/SynchronizedDemo.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.demo.lock;
2 |
3 | /**
4 | * @author TommyYang on 2019/1/28
5 | */
6 | public class SynchronizedDemo implements Runnable {
7 |
8 | public static int common = 0;
9 |
10 | public void run() {
11 | for(int j=0;j<1000000;j++){
12 | this.add();
13 | }
14 | }
15 |
16 | public synchronized void add(){
17 | synchronized (this){
18 | common++;
19 | }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/lock/src/main/java/cn/tommyyang/distributedlock/RedisDistributedLock.java:
--------------------------------------------------------------------------------
1 | package cn.tommyyang.distributedlock;
2 |
3 | /**
4 | * @author TommyYang on 2019-05-12
5 | */
6 | public class RedisDistributedLock {
7 |
8 |
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/machinelearning/recommend_system.md:
--------------------------------------------------------------------------------
1 | # 推荐系统整理
2 | 该篇主要对推荐系统进行一些整理。
3 |
4 | ## 推荐系统涉及到的一些模块
5 | 核心模块有用户、Item(包括文章、视频、商品、音乐、电影等)、用户实时画像、Item 特征等。
6 | 核心服务有召回服务、推荐服务、排序服务等。
7 |
8 | 如下图:
9 | 
10 |
11 | 比较重要就是要去了解 NLP(自然语言处理),基于 NLP 的特征分析。基于模型的排序服务,比如决策树、FM 模型、FFM 模型、双线性 FFM 模型、DNN、Wide&Deep 等。排序模型个人觉得讲的比较好的一篇文章,[推荐排序模型](https://www.infoq.cn/article/vKoKh_ZDXcWRh8fLSsRp)。
12 |
13 | ## 推荐模型时序图
14 | 
15 |
16 | - 1.2.3 和 1.2.4 应该是在一步同时异步执行的
17 | - 1.3 获取文章title、content、发布时间、作者等相关信息
18 | - 1.2.3 里面包括 label 画像召回、LDA(Topic) 画像召回、用户与作者亲密度召回(我理解为基于社交关系的召回,这一类文章加上推荐理由效果会更好)
19 |
20 | tips: 为什么 Doc2vec 画像单独弄成一个微服务,因为 vector 是一个 300 维的 float 类型的数组,计算量特别大;所以做成 T+1 模式,提前计算好,然后索引到文件中。(使用的是开源的 Annoy 进行文件索引)。
21 |
22 | ## 实时画像时序图
23 | 
24 |
25 | - 流处理框架使用当下比较流行的 Flink。
26 | - Flink 支持批量和流处理两种模式。
27 | - 批量计算时只是对接数据源不一样,数据仓库大多数为 Hive。
28 |
29 | ## 数据分析
30 | 通过之前做过的一些视频、文章推荐举例。
31 |
32 | - 多策略召回。
33 | - Rank 模型训练特征由离线转为实时。
34 | - 特征精细化,比如由文章总体 CTR 变为每个策略下的 CTR;不同分类下文章的时效性不一样,所以 CTR 计算周期不一样,比如有的文章在一开始 CTR 特别高,但随着时间变化,慢慢降低,但是相比其它的一些文章,还是很高,这时候,就需要调整 CTR 计算周期。
35 | - 分析重要的特征加入到训练模型,比如对文章来说:CTR、CDR;统计用户在每个分类下的 CTR、CDR,可以更加具体的描述出用户对不同分类的喜欢程度。
36 |
37 | ## 名词介绍
38 | - CTR:Click-Through-Rate,点击通过率。
39 | - CDR:Completion-reaDing-Rate,阅读完成率。
40 |
41 | ## 文章推荐
42 | - [从 FFM 到 DeepFFM,推荐排序模型到底哪家强?](https://www.infoq.cn/article/vKoKh_ZDXcWRh8fLSsRp)
43 | - [NLP](https://easyai.tech/ai-definition/nlp/)
44 | - [LDA](https://www.hankcs.com/nlp/lda-java-introduction-and-implementation.html)
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/machinelearning/tensorflow.md:
--------------------------------------------------------------------------------
1 | # tensorflow 入门
2 | ## 环境搭建
--------------------------------------------------------------------------------
/mymp.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/mymp.jpeg
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | cn.tommyyang
8 | javainterview
9 | pom
10 | 1.0-SNAPSHOT
11 |
12 | sortpro
13 | web
14 | lock
15 | bigdata
16 | codeinterview
17 | io
18 | test
19 | javabase/datastructure
20 | architecture
21 | javabase/java8
22 | javabase/keywords
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/sortpro/1.bubbleSort.md:
--------------------------------------------------------------------------------
1 | # 冒泡排序
2 |
3 | 冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
4 |
5 | 作为最简单的排序算法之一,冒泡排序给我的感觉就像 Abandon 在单词书里出现的感觉一样,每次都在第一页第一位,所以最熟悉。冒泡排序还有一种优化算法,就是立一个 flag,当在一趟序列遍历中元素没有发生交换,则证明该序列已经有序。但这种改进对于提升性能来说并没有什么太大作用。
6 |
7 |
8 | ## 1. 算法步骤
9 |
10 | 1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
11 |
12 | 2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
13 |
14 | 3. 针对所有的元素重复以上的步骤,除了最后一个。
15 |
16 | 4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
17 |
18 |
19 | ## 2. 动图演示
20 |
21 | 
22 |
23 |
24 | ## 3. 什么时候最快
25 |
26 | 当输入的数据已经是正序时(都已经是正序了,我还要你冒泡排序有何用啊)。
27 |
28 |
29 | ## 4. 什么时候最慢
30 |
31 | 当输入的数据是反序时(写一个 for 循环反序输出数据不就行了,干嘛要用你冒泡排序呢,我是闲的吗)。
--------------------------------------------------------------------------------
/sortpro/10.radixSort.md:
--------------------------------------------------------------------------------
1 | # 基数排序
2 |
3 | 基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
4 |
5 |
6 | ## 1. 基数排序 vs 计数排序 vs 桶排序
7 |
8 | 基数排序有两种方法:
9 |
10 | 这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:
11 |
12 | - 基数排序:根据键值的每位数字来分配桶;
13 | - 计数排序:每个桶只存储单一键值;
14 | - 桶排序:每个桶存储一定范围的数值;
15 |
16 |
17 | ## 2. LSD 基数排序动图演示
18 |
19 | 
--------------------------------------------------------------------------------
/sortpro/2.selectionSort.md:
--------------------------------------------------------------------------------
1 | # 选择排序
2 |
3 | 选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。
4 |
5 |
6 | ## 1. 算法步骤
7 |
8 | 1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
9 |
10 | 2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
11 |
12 | 3. 重复第二步,直到所有元素均排序完毕。
13 |
14 |
15 | ## 2. 动图演示
16 |
17 | 
18 |
--------------------------------------------------------------------------------
/sortpro/3.insertionSort.md:
--------------------------------------------------------------------------------
1 | # 插入排序
2 |
3 | 插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
4 |
5 | 插入排序和冒泡排序一样,也有一种优化算法,叫做拆半插入。
6 |
7 |
8 | ## 1. 算法步骤
9 |
10 | 1. 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
11 |
12 | 2. 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
13 |
14 |
15 | ## 2. 动图演示
16 |
17 | 
18 |
--------------------------------------------------------------------------------
/sortpro/4.shellSort.md:
--------------------------------------------------------------------------------
1 | # 希尔排序
2 |
3 | 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
4 |
5 | 希尔排序是基于插入排序的以下两点性质而提出改进方法的:
6 |
7 | - 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
8 | - 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
9 |
10 | 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
11 |
12 |
13 | ## 1. 算法步骤
14 |
15 | 1. 选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
16 |
17 | 2. 按增量序列个数 k,对序列进行 k 趟排序;
18 |
19 | 3. 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
--------------------------------------------------------------------------------
/sortpro/5.mergeSort.md:
--------------------------------------------------------------------------------
1 | # 归并排序
2 |
3 | 归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
4 |
5 | 作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:
6 | - 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
7 | - 自下而上的迭代;
8 |
9 | 在《数据结构与算法 JavaScript 描述》中,作者给出了自下而上的迭代方法。但是对于递归法,作者却认为:
10 |
11 | > However, it is not possible to do so in JavaScript, as the recursion goes too deep for the language to handle.
12 | >
13 | > 然而,在 JavaScript 中这种方式不太可行,因为这个算法的递归深度对它来讲太深了。
14 |
15 |
16 | 说实话,我不太理解这句话。意思是 JavaScript 编译器内存太小,递归太深容易造成内存溢出吗?还望有大神能够指教。
17 |
18 | 和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是 O(nlogn) 的时间复杂度。代价是需要额外的内存空间。
19 |
20 |
21 | ## 2. 算法步骤
22 |
23 | 1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
24 |
25 | 2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
26 |
27 | 3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
28 |
29 | 4. 重复步骤 3 直到某一指针达到序列尾;
30 |
31 | 5. 将另一序列剩下的所有元素直接复制到合并序列尾。
32 |
33 |
34 | ## 3. 动图演示
35 |
36 | 
--------------------------------------------------------------------------------
/sortpro/6.quickSort.md:
--------------------------------------------------------------------------------
1 | # 快速排序
2 |
3 | 快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
4 |
5 | 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
6 |
7 | 快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。
8 |
9 | 快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高!它是处理大数据最快的排序算法之一了。虽然 Worst Case 的时间复杂度达到了 O(n²),但是人家就是优秀,在大多数情况下都比平均时间复杂度为 O(n logn) 的排序算法表现要更好,可是这是为什么呢,我也不知道。好在我的强迫症又犯了,查了 N 多资料终于在《算法艺术与信息学竞赛》上找到了满意的答案:
10 |
11 | > 快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。
12 |
13 |
14 | ## 1. 算法步骤
15 |
16 | 1. 从数列中挑出一个元素,称为 “基准”(pivot);
17 |
18 | 2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
19 |
20 | 3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
21 |
22 | 递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
23 |
24 |
25 | ## 2. 动图演示
26 |
27 | 
--------------------------------------------------------------------------------
/sortpro/7.heapSort.md:
--------------------------------------------------------------------------------
1 | # 堆排序
2 |
3 | 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:
4 |
5 | 1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
6 | 2. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;
7 |
8 | 堆排序的平均时间复杂度为 Ο(nlogn)。
9 |
10 |
11 | ## 1. 算法步骤
12 |
13 | 1. 创建一个堆 H[0……n-1];
14 |
15 | 2. 把堆首(最大值)和堆尾互换;
16 |
17 | 3. 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;
18 |
19 | 4. 重复步骤 2,直到堆的尺寸为 1。
20 |
21 |
22 | ## 2. 动图演示
23 |
24 | 
--------------------------------------------------------------------------------
/sortpro/8.countingSort.md:
--------------------------------------------------------------------------------
1 | # 计数排序
2 |
3 | 计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
4 |
5 | ## 1. 动图演示
6 |
7 | 
--------------------------------------------------------------------------------
/sortpro/9.bucketSort.md:
--------------------------------------------------------------------------------
1 | # 桶排序
2 |
3 | 桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点:
4 |
5 | 1. 在额外空间充足的情况下,尽量增大桶的数量
6 | 2. 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中
7 |
8 | 同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。
9 |
10 |
11 | ## 1. 什么时候最快
12 |
13 | 当输入的数据可以均匀的分配到每一个桶中。
14 |
15 |
16 | ## 2. 什么时候最慢
17 |
18 | 当输入的数据被分配到了同一个桶中。
--------------------------------------------------------------------------------
/sortpro/README.md:
--------------------------------------------------------------------------------
1 | # 排序篇
2 |
3 | 排序算法是《数据结构与算法》中最基本的算法之一。
4 | 因为排序在日常编程中是出现的最频繁的一种算法,所以单独用一个篇章来整理。
5 |
6 | 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:**插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序**等。用一张图概括:
7 |
8 | 
9 |
10 |
11 | **关于时间复杂度**:
12 |
13 | 1. 平方阶 (O(n2)) 排序
14 | 各类简单排序:直接插入、直接选择和冒泡排序。
15 | 2. 线性对数阶 (O(nlog2n)) 排序
16 | 快速排序、堆排序和归并排序;
17 | 3. O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。
18 | 希尔排序
19 | 4. 线性阶 (O(n)) 排序
20 | 基数排序,此外还有桶、箱排序。
21 |
22 |
23 | **关于稳定性**:
24 |
25 | 稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。
26 |
27 | 不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。
28 |
29 |
30 | **名词解释**:
31 |
32 | **n**:数据规模
33 |
34 | **k**:“桶”的个数
35 |
36 | **In-place**:占用常数内存,不占用额外内存
37 |
38 | **Out-place**:占用额外内存
39 |
40 | **稳定性**:排序后 2 个相等键值的顺序和排序之前它们的顺序相同
41 |
42 | ----
43 |
44 |
45 | **目录**
46 |
47 | 1. [冒泡排序](1.bubbleSort.md)
48 | 2. [选择排序](2.selectionSort.md)
49 | 3. [插入排序](3.insertionSort.md)
50 | 4. [希尔排序](4.shellSort.md)
51 | 5. [归并排序](5.mergeSort.md)
52 | 6. [快速排序](6.quickSort.md)
53 | 7. [堆排序](7.heapSort.md)
54 | 8. [计数排序](8.countingSort.md)
55 | 9. [桶排序](9.bucketSort.md)
56 | 10. [基数排序](10.radixSort.md)
57 |
58 | ----
59 |
60 | 本篇内容几乎完全来源于网络,动图演示感谢hustcc,来自于hustcc的项目。
--------------------------------------------------------------------------------
/sortpro/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | javainterview
7 | cn.tommyyang
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | sortpro
13 |
14 |
15 |
16 | org.apache.maven.plugins
17 | maven-compiler-plugin
18 |
19 | 1.8
20 | 1.8
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/sortpro/res/bubbleSort.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/sortpro/res/bubbleSort.gif
--------------------------------------------------------------------------------
/sortpro/res/countingSort.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/sortpro/res/countingSort.gif
--------------------------------------------------------------------------------
/sortpro/res/heapSort.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/sortpro/res/heapSort.gif
--------------------------------------------------------------------------------
/sortpro/res/insertionSort.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/sortpro/res/insertionSort.gif
--------------------------------------------------------------------------------
/sortpro/res/mergeSort.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/sortpro/res/mergeSort.gif
--------------------------------------------------------------------------------
/sortpro/res/quickSort.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/sortpro/res/quickSort.gif
--------------------------------------------------------------------------------
/sortpro/res/radixSort.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/sortpro/res/radixSort.gif
--------------------------------------------------------------------------------
/sortpro/res/selectionSort.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/sortpro/res/selectionSort.gif
--------------------------------------------------------------------------------
/sortpro/res/sort.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joyang1/JavaInterview/4876ef24f0d28c5f0d15c0b19a369e24f43bdf38/sortpro/res/sort.png
--------------------------------------------------------------------------------
/sortpro/src/main/java/Run.java:
--------------------------------------------------------------------------------
1 | import sort.*;
2 |
3 | /**
4 | * Created by TommyYang on 2018/3/9.
5 | */
6 | public class Run {
7 |
8 | public static void main(String[] args) {
9 | int[] arr = new int[]{2, 2, 23, 5, 4, 5, 3, 3};
10 | IArraySort bubbleSort = new BubbleSort();
11 | IArraySort countingSort = new CountingSort();
12 | IArraySort insertSort = new InsertSort();
13 | IArraySort selectionSort = new SelectionSort();
14 | IArraySort shellSort = new ShellSort();
15 | IArraySort mergeSort = new MergeSort();
16 | IArraySort quickSort = new QuickSort();
17 | IArraySort quickSort1 = new QuickSort1();
18 | IArraySort heapSort = new HeapSort();
19 | IArraySort bucketSort = new BucketSort();
20 | IArraySort radixSort = new RadixSort();
21 | try {
22 | //int[] desArr = bubbleSort.sort(arr);
23 | //int[] desArr = countingSort.sort(arr);
24 | //int[] desArr = insertSort.sort(arr);
25 | //int[] desArr = selectionSort.sort(arr);
26 | //int[] desArr = shellSort.sort(arr);
27 | //int[] desArr = mergeSort.sort(arr);
28 | //int[] desArr = quickSort.sort(arr);
29 | //int[] desArr = heapSort.sort(arr);
30 | //int[] desArr = bucketSort.sort(arr);
31 | int[] desArr = quickSort1.sort(arr);
32 | System.out.println("排序结果:");
33 | for (Integer i : desArr) {
34 | System.out.print(i);
35 | System.out.print("\t");
36 | }
37 | } catch (Exception e) {
38 | System.out.println(e);
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/search/BinarySearch.java:
--------------------------------------------------------------------------------
1 | package search;
2 |
3 | /**
4 | * @author TommyYang on 2019-04-12
5 | */
6 | public class BinarySearch {
7 |
8 | //循环实现
9 | public static int binarySearch(int[] arr, int target){
10 | int low = 0, high = arr.length - 1;
11 |
12 | while (low <= high){
13 | int mid = low + (high - low) / 2;
14 | if (arr[mid] < target) low = mid + 1;
15 | else if (arr[mid] > target) high = mid - 1;
16 | else return mid;
17 | }
18 |
19 | return -1;
20 | }
21 |
22 | //递归实现
23 | public static int binarySearchRecur(int[] arr, int target, int low, int high){
24 |
25 | if (low > high){
26 | return -1;
27 | }
28 |
29 | int mid = low + (high - low) / 2;
30 |
31 | if(arr[mid] < target){
32 | return binarySearchRecur(arr, target, mid + 1, high);
33 | } else if(arr[mid] > target){
34 | return binarySearchRecur(arr, target, low, mid - 1);
35 | } else {
36 | return mid;
37 | }
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/BubbleSort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * Created by TommyYang on 2018/3/9.
7 | */
8 | /**
9 | * 冒泡排序
10 | */
11 | public class BubbleSort implements IArraySort {
12 |
13 | @Override
14 | public int[] sort(int[] sourArr) throws Exception {
15 | // 对 sourceArr 进行拷贝,不改变参数内容
16 | int[] desArr = Arrays.copyOf(sourArr, sourArr.length);
17 |
18 | for (int i = 0; i < desArr.length ; i++){
19 | //设置一个标志,用来判断该数组是否已经有序,提高效率
20 | Boolean flag = Boolean.TRUE;
21 |
22 | //该处一定要是desArr.length - i - 1,切记不能是desArr.length - i
23 | for(int j = 0; j < desArr.length - i - 1; j ++){
24 | if(desArr[j] > desArr[j+1]){
25 | int temp = desArr[j];
26 | desArr[j] = desArr[j+1];
27 | desArr[j+1] = temp;
28 | flag = false;
29 | }
30 | }
31 | if(flag){
32 | break;
33 | }
34 | }
35 | return desArr;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/BucketSort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * Created by TommyYang on 2018/3/9.
7 | */
8 | public class BucketSort implements IArraySort {
9 |
10 | private static final InsertSort insertSort = new InsertSort();
11 |
12 | @Override
13 | public int[] sort(int[] sourceArray) throws Exception {
14 | // 对 arr 进行拷贝,不改变参数内容
15 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
16 |
17 | return bucketSort(arr, 5);
18 | }
19 |
20 | private int[] bucketSort(int[] arr, int bucketSize) throws Exception {
21 | if (arr.length == 0) {
22 | return arr;
23 | }
24 |
25 | int minValue = arr[0];
26 | int maxValue = arr[0];
27 | for (int value : arr) {
28 | if (value < minValue) {
29 | minValue = value;
30 | } else if (value > maxValue) {
31 | maxValue = value;
32 | }
33 | }
34 |
35 | int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1;
36 | int[][] buckets = new int[bucketCount][0];
37 |
38 | // 利用映射函数将数据分配到各个桶中
39 | for (int i = 0; i < arr.length; i++) {
40 | int index = (int) Math.floor((arr[i] - minValue) / bucketSize);
41 | buckets[index] = arrAppend(buckets[index], arr[i]);
42 | }
43 |
44 | int arrIndex = 0;
45 | for (int[] bucket : buckets) {
46 | if (bucket.length <= 0) {
47 | continue;
48 | }
49 | // 对每个桶进行排序,这里使用了插入排序
50 | bucket = insertSort.sort(bucket);
51 | for (int value : bucket) {
52 | arr[arrIndex++] = value;
53 | }
54 | }
55 |
56 | return arr;
57 | }
58 |
59 | /**
60 | * 自动扩容,并保存数据
61 | *
62 | * @param arr
63 | * @param value
64 | */
65 | private int[] arrAppend(int[] arr, int value) {
66 | arr = Arrays.copyOf(arr, arr.length + 1);
67 | arr[arr.length - 1] = value;
68 | return arr;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/CountingSort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | /**
4 | * Created by TommyYang on 2018/3/9.
5 | */
6 |
7 | import java.util.Arrays;
8 |
9 | /**
10 | * 计数排序
11 | */
12 | public class CountingSort implements IArraySort {
13 |
14 | @Override
15 | public int[] sort(int[] sourceArr) throws Exception {
16 | // 对 sourceArr 进行拷贝,不改变参数内容
17 | int[] arr = Arrays.copyOf(sourceArr, sourceArr.length);
18 |
19 | int maxValue = getMaxValue(arr);
20 |
21 | return countingSort(arr, maxValue);
22 | }
23 |
24 | private int[] countingSort(int[] arr, int maxValue) {
25 | int bucketLen = maxValue + 1;
26 | int[] bucket = new int[bucketLen];
27 |
28 | for (int value : arr) {
29 | bucket[value]++;
30 | }
31 |
32 | int sortedIndex = 0;
33 | for (int j = 0; j < bucketLen; j++) {
34 | while (bucket[j] > 0) {
35 | arr[sortedIndex++] = j;
36 | bucket[j]--;
37 | }
38 | }
39 | return arr;
40 | }
41 |
42 | private int getMaxValue(int[] arr) {
43 | int maxValue = arr[0];
44 | for (int value : arr) {
45 | if (maxValue < value) {
46 | maxValue = value;
47 | }
48 | }
49 | return maxValue;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/HeapSort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * Created by TommyYang on 2018/3/12.
7 | */
8 | public class HeapSort implements IArraySort {
9 | @Override
10 | public int[] sort(int[] sourceArray) throws Exception {
11 | // 对 arr 进行拷贝,不改变参数内容
12 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
13 |
14 | int len = arr.length;
15 |
16 | buildMaxHeap(arr, len);
17 |
18 | for (int i = len - 1; i > 0; i--) {
19 | swap(arr, 0, i);
20 | len--;
21 | heapify(arr, 0, len);
22 | }
23 | return arr;
24 | }
25 |
26 | private void buildMaxHeap(int[] arr, int len) {
27 | for (int i = (int) Math.floor(len / 2); i >= 0; i--) {
28 | heapify(arr, i, len);
29 | }
30 | }
31 |
32 | private void heapify(int[] arr, int i, int len) {
33 | int left = 2 * i + 1;
34 | int right = 2 * i + 2;
35 | int largest = i;
36 |
37 | if (left < len && arr[left] > arr[largest]) {
38 | largest = left;
39 | }
40 |
41 | if (right < len && arr[right] > arr[largest]) {
42 | largest = right;
43 | }
44 |
45 | if (largest != i) {
46 | swap(arr, i, largest);
47 | heapify(arr, largest, len);
48 | }
49 | }
50 |
51 | private void swap(int[] arr, int i, int j) {
52 | int temp = arr[i];
53 | arr[i] = arr[j];
54 | arr[j] = temp;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/IArraySort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | /**
4 | * Created by TommyYang on 2018/3/9.
5 | */
6 | public interface IArraySort {
7 |
8 | /**
9 | *
10 | * 对数组进行排序,并返回排序后的数组
11 | *
12 | * @param sourArr
13 | * @return int[]
14 | * @throws Exception
15 | */
16 |
17 | int[] sort(int[] sourArr) throws Exception;
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/InsertSort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * Created by TommyYang on 2018/3/9.
7 | */
8 | public class InsertSort implements IArraySort {
9 |
10 | @Override
11 | public int[] sort(int[] sourArr) throws Exception {
12 | // 对 sourceArr 进行拷贝,不改变参数内容
13 | int[] desArr = Arrays.copyOf(sourArr, sourArr.length);
14 |
15 | for (int i = 1; i < desArr.length ; i++){
16 | int tmp = desArr[i];
17 |
18 | int j = i;
19 | while (j > 0 && tmp < desArr[j - 1]){
20 | desArr[j] = desArr[j - 1];
21 | j--;
22 | }
23 | if(j != i){
24 | desArr[j] = tmp;
25 | }
26 | }
27 | return desArr;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/MergeSort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * Created by TommyYang on 2018/3/12.
7 | */
8 | public class MergeSort implements IArraySort {
9 |
10 | @Override
11 | public int[] sort(int[] sourArr) throws Exception {
12 | // 对 sourceArr 进行拷贝,不改变参数内容
13 | int[] desArr = Arrays.copyOf(sourArr, sourArr.length);
14 |
15 | if (desArr.length < 2) {
16 | return desArr;
17 | }
18 |
19 | int middle = (int) Math.floor(desArr.length / 2);
20 | int[] left = Arrays.copyOfRange(desArr, 0, middle);
21 | int[] right = Arrays.copyOfRange(desArr, middle, desArr.length);
22 |
23 | return this.merge(sort(left), sort(right));
24 | }
25 |
26 | protected int[] merge(int[] left, int[] right) {
27 | int[] result = new int[left.length + right.length];
28 | int i = 0;
29 | while (left.length > 0 && right.length > 0) {
30 | if (left[0] <= right[0]) {
31 | result[i++] = left[0];
32 | left = Arrays.copyOfRange(left, 1, left.length);
33 | } else {
34 | result[i++] = right[0];
35 | right = Arrays.copyOfRange(right, 1, right.length);
36 | }
37 | }
38 | while (left.length > 0) {
39 | result[i++] = left[0];
40 | left = Arrays.copyOfRange(left, 1, left.length);
41 | }
42 | while (right.length > 0) {
43 | result[i++] = right[0];
44 | right = Arrays.copyOfRange(right, 1, right.length);
45 | }
46 | return result;
47 | }
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/QuickSort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * Created by TommyYang on 2018/3/12.
7 | */
8 | public class QuickSort implements IArraySort {
9 | @Override
10 | public int[] sort(int[] sourceArray) throws Exception {
11 | // 对 arr 进行拷贝,不改变参数内容
12 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
13 |
14 | return quickSort(arr, 0, arr.length - 1);
15 | }
16 |
17 | private int[] quickSort(int[] arr, int left, int right) {
18 | if (left < right) {
19 | int partitionIndex = partition(arr, left, right);
20 | quickSort(arr, left, partitionIndex - 1);
21 | quickSort(arr, partitionIndex + 1, right);
22 | }
23 | return arr;
24 | }
25 |
26 | private int partition(int[] arr, int left, int right) {
27 | // 设定基准值(pivot)
28 | int pivot = left;
29 | int index = pivot + 1;
30 | for (int i = index; i <= right; i++) {
31 | if (arr[i] < arr[pivot]) {
32 | swap(arr, i, index);
33 | index++;
34 | }
35 | }
36 | swap(arr, pivot, index - 1);
37 | return index - 1;
38 | }
39 |
40 | private void swap(int[] arr, int i, int j) {
41 | int temp = arr[i];
42 | arr[i] = arr[j];
43 | arr[j] = temp;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/QuickSort1.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * @author TommyYang on 2019-04-12
7 | */
8 | public class QuickSort1 implements IArraySort {
9 |
10 | public void quickSort(int[] arr, int left, int right) {
11 |
12 | if(left >= right){
13 | return;
14 | }
15 |
16 | int partition = partition(arr, left, right);
17 |
18 | quickSort(arr, left, partition - 1);
19 | quickSort(arr, partition + 1, right);
20 |
21 | }
22 |
23 |
24 | public int partition(int[] arr, int i, int j) {
25 | int pivot = arr[i];
26 | while (i < j) {
27 | while (i < j && arr[j] > pivot)
28 | j--;
29 | if (i < j) {
30 | arr[i] = arr[j];
31 | i++;
32 | }
33 |
34 | while (i < j && arr[i] < pivot)
35 | i++;
36 |
37 | if (i < j) {
38 | arr[j] = arr[i];
39 | j--;
40 | }
41 | }
42 |
43 | arr[i] = pivot;
44 | return i;
45 |
46 | }
47 |
48 | @Override
49 | public int[] sort(int[] sourArr) throws Exception {
50 | // 对 arr 进行拷贝,不改变参数内容
51 | int[] arr = Arrays.copyOf(sourArr, sourArr.length);
52 |
53 | quickSort(arr, 0, arr.length - 1);
54 |
55 | return arr;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/RadixSort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * Created by TommyYang on 2018/3/12.
7 | */
8 | public class RadixSort implements IArraySort {
9 | @Override
10 | public int[] sort(int[] sourceArray) throws Exception {
11 | // 对 arr 进行拷贝,不改变参数内容
12 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
13 |
14 | int maxDigit = getMaxDigit(arr);
15 | return radixSort(arr, maxDigit);
16 | }
17 |
18 | /**
19 | * 获取最高位数
20 | */
21 | private int getMaxDigit(int[] arr) {
22 | int maxValue = getMaxValue(arr);
23 | return getNumLenght(maxValue);
24 | }
25 |
26 | private int getMaxValue(int[] arr) {
27 | int maxValue = arr[0];
28 | for (int value : arr) {
29 | if (maxValue < value) {
30 | maxValue = value;
31 | }
32 | }
33 | return maxValue;
34 | }
35 |
36 | protected int getNumLenght(long num) {
37 | if (num == 0) {
38 | return 1;
39 | }
40 | int lenght = 0;
41 | for (long temp = num; temp != 0; temp /= 10) {
42 | lenght++;
43 | }
44 | return lenght;
45 | }
46 |
47 | private int[] radixSort(int[] arr, int maxDigit) {
48 | int mod = 10;
49 | int dev = 1;
50 |
51 | for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
52 | // 考虑负数的情况,这里扩展一倍队列数,其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10)
53 | int[][] counter = new int[mod * 2][0];
54 |
55 | for (int j = 0; j < arr.length; j++) {
56 | int bucket = ((arr[j] % mod) / dev) + mod;
57 | counter[bucket] = arrayAppend(counter[bucket], arr[j]);
58 | }
59 |
60 | int pos = 0;
61 | for (int[] bucket : counter) {
62 | for (int value : bucket) {
63 | arr[pos++] = value;
64 | }
65 | }
66 | }
67 |
68 | return arr;
69 | }
70 |
71 | /**
72 | * 自动扩容,并保存数据
73 | *
74 | * @param arr
75 | * @param value
76 | */
77 | private int[] arrayAppend(int[] arr, int value) {
78 | arr = Arrays.copyOf(arr, arr.length + 1);
79 | arr[arr.length - 1] = value;
80 | return arr;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/SelectionSort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * Created by TommyYang on 2018/3/12.
7 | */
8 | public class SelectionSort implements IArraySort {
9 |
10 | @Override
11 | public int[] sort(int[] sourArr) throws Exception {
12 | // 对 sourceArr 进行拷贝,不改变参数内容
13 | int[] desArr = Arrays.copyOf(sourArr, sourArr.length);
14 |
15 | //此处记住要-1, 需进行n-1轮比较
16 | for (int i = 0; i < desArr.length - 1; i++){
17 | int min = i;
18 | //每轮需进行n-i次比较
19 | for (int j = i+1; j < desArr.length; j++){
20 | if(desArr[j] < desArr[min]){
21 | min = j; //每轮找到最小数位置的下标
22 | }
23 | }
24 |
25 | // 将找到的最小值和i位置所在的值进行交换
26 | if(min != i){
27 | int tmp = desArr[i];
28 | desArr[i] = desArr[min];
29 | desArr[min] = tmp;
30 | }
31 | }
32 |
33 | return desArr;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/sortpro/src/main/java/sort/ShellSort.java:
--------------------------------------------------------------------------------
1 | package sort;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * Created by TommyYang on 2018/3/12.
7 | */
8 | public class ShellSort implements IArraySort {
9 |
10 | @Override
11 | public int[] sort(int[] sourArr) throws Exception {
12 | // 对 sourceArr 进行拷贝,不改变参数内容
13 | int[] desArr = Arrays.copyOf(sourArr, sourArr.length);
14 | int gap = 1;
15 | while (gap < desArr.length / 4){ //动态定义间隔序列
16 | gap = gap * 4 + 1;
17 | }
18 |
19 | while (gap > 0){
20 | for (int i = gap; i < desArr.length; i++){
21 | int tmp = desArr[i];
22 | int j = i - gap;
23 | while (j >= 0 && desArr[j] > tmp){
24 | desArr[j + gap] = desArr[j];
25 | j -= gap;
26 | }
27 | desArr[j + gap] = tmp;
28 | }
29 | gap = (int)Math.floor(gap / 3);
30 | }
31 |
32 | return desArr;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/test/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | javainterview
7 | cn.tommyyang
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | test
13 |
14 |
15 |
16 | io.grpc
17 | grpc-netty-shaded
18 | 1.20.0
19 |
20 |
21 | io.grpc
22 | grpc-protobuf
23 | 1.20.0
24 |
25 |
26 | io.grpc
27 | grpc-stub
28 | 1.20.0
29 |
30 |
31 | com.alibaba
32 | fastjson
33 | 1.2.60
34 |
35 |
36 | commons-beanutils
37 | commons-beanutils
38 | 1.8.0
39 |
40 |
41 | org.apache.commons
42 | commons-collections4
43 | 4.1
44 |
45 |
46 |
47 |
48 |
49 |
50 | kr.motd.maven
51 | os-maven-plugin
52 | 1.5.0.Final
53 |
54 |
55 |
56 |
57 |
58 | org.xolstice.maven.plugins
59 | protobuf-maven-plugin
60 | 0.5.1
61 |
62 | ${project.basedir}/src/main/protos
63 | com.google.protobuf:protoc:3.6.1:exe:${os.detected.classifier}
64 | grpc-java
65 | io.grpc:protoc-gen-grpc-java:1.19.0:exe:${os.detected.classifier}
66 | ${project.basedir}/src/main/java/
67 | false
68 |
69 |
70 |
71 |
72 | compile
73 | compile-custom
74 |
75 |
76 |
77 |
78 |
79 | org.apache.maven.plugins
80 | maven-compiler-plugin
81 |
82 | 1.8
83 | 1.8
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/test/src/main/java/HiveTableChange.java:
--------------------------------------------------------------------------------
1 | import java.util.stream.IntStream;
2 |
3 | /**
4 | * @Author : TommyYang
5 | * @Time : 2019-08-22 11:29
6 | * @Software: IntelliJ IDEA
7 | * @File : HiveTableChange.java
8 | */
9 | public class HiveTableChange {
10 |
11 | // CASCADE; add or replace column with CASCADE will update table and partition metadata;
12 |
13 | public static void main(String[] args) {
14 | StringBuilder sBuilder = new StringBuilder("ALTER TABLE hdfs.rank_user_features ADD COLUMNS (");
15 | // StringBuilder sBuilder = new StringBuilder("CREATE EXTERNAL TABLE `hdfs.rank_user_features`(");
16 | builder(sBuilder, "add");
17 |
18 | System.out.println(sBuilder.toString());
19 | }
20 |
21 | private static void builder(StringBuilder sBuilder, String mode) {
22 | if (!mode.equals("add")) {
23 | sBuilder.append("`batch_id` string, ").append(" `gender` int, ")
24 | .append("`entity_type` string, ").append("`entity_id` string, ");
25 |
26 | IntStream.range(1, 86).forEach(index -> {
27 | String latesClickStr = String.format("`click_label%d` int", index);
28 | sBuilder.append(latesClickStr).append(", ");
29 | });
30 |
31 | IntStream.range(1, 86).forEach(index -> {
32 | String latesClickStr = String.format("`impr_label%d` int", index);
33 | sBuilder.append(latesClickStr).append(", ");
34 | });
35 |
36 | IntStream.range(1, 86).forEach(index -> {
37 | String latesClickStr = String.format("`read_label%d` int", index);
38 | sBuilder.append(latesClickStr).append(", ");
39 | });
40 | }
41 |
42 | IntStream.range(1, 86).forEach(index -> {
43 | String latesClickStr = String.format("`latest_click_label%d` int", index);
44 | sBuilder.append(latesClickStr).append(", ");
45 | });
46 |
47 | IntStream.range(1, 86).forEach(index -> {
48 | String latesClickStr = String.format("`latest_impr_label%d` int", index);
49 | sBuilder.append(latesClickStr).append(", ");
50 | });
51 |
52 | IntStream.range(1, 86).forEach(index -> {
53 | String latesClickStr = String.format("`latest_read_label%d` int", index);
54 | if (index < 85) {
55 | sBuilder.append(latesClickStr).append(",");
56 | } else {
57 | sBuilder.append(latesClickStr);
58 | }
59 | });
60 |
61 | if (mode.equals("add")){
62 | sBuilder.append(") CASCADE;");
63 | } else if (mode.equals("replace")) {
64 | sBuilder.append(",dt string) CASCADE;");
65 | } else if (mode.equals("create")) {
66 | sBuilder.append(")\n");
67 | sBuilder.append("PARTITIONED BY (`dt` string)\n")
68 | .append("ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'\n")
69 | .append("WITH SERDEPROPERTIES ('field.delim'='\\t', 'serialization.format'='\\t')\n")
70 | .append("STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat'\n")
71 | .append("OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'\n")
72 | .append("LOCATION 'hdfs://ns1/data/frontpagenote_recommend_records/user_features';");
73 | }
74 |
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/test/src/main/java/StringUitls.java:
--------------------------------------------------------------------------------
1 | import java.io.IOException;
2 | import java.nio.charset.Charset;
3 | import java.nio.file.Files;
4 | import java.nio.file.Paths;
5 | import java.util.stream.Stream;
6 |
7 | /**
8 | * @Author : TommyYang
9 | * @Time : 2019-09-17 16:23
10 | * @Software: IntelliJ IDEA
11 | * @File : StringUitls.java
12 | */
13 | public class StringUitls {
14 |
15 | public static void main(String[] args) throws IOException {
16 | Stream lines = Files.lines(Paths.get("/Users/tommy/Documents/aa.txt"), Charset.defaultCharset());
17 | lines.forEach(line -> {
18 | // System.out.println(line.trim());
19 | int start = line.trim().indexOf(">");
20 | int end = line.trim().lastIndexOf("<");
21 | String value = line.trim().substring(start + 1, end);
22 | line = line.trim().replace("