From 064c24f8acb1e5292635703d89e92a2bd0a004eb Mon Sep 17 00:00:00 2001 From: "haiji.yang" Date: Fri, 4 Dec 2020 16:39:20 +0800 Subject: [PATCH] add --- note/actualCombat/Limiter.md | 2 +- note/java/concurrency/README.md | 2 + .../designpattern/ThreadPerMessage.md | 156 ++++++++++++++++++ .../concurrency/designpattern/WorkerThread.md | 141 ++++++++++++++++ .../designpattern/img/token.drawio | 1 + .../javayh/advanced/AdvancedApplication.java | 5 +- .../config/AutoIdempotentInterceptor.java | 10 +- .../advanced/config/WebConfiguration.java | 1 + .../exception/ExceptionBoundaryViolation.java | 2 +- .../exception/ExceptionPositionInvalid.java | 2 +- .../exception/ExceptionStackEmpty.java | 4 +- .../exception/ExceptionStackFull.java | 2 +- .../advanced/exception/ServerException.java | 2 +- .../java/ExamplesEnum/ExamplesEnum.java | 12 +- ...\346\263\241\346\216\222\345\272\217.java" | 8 +- ...\345\205\245\346\216\222\345\272\217.java" | 1 + ...\346\225\260\347\233\270\345\212\240.java" | 16 +- ...\345\210\206\346\237\245\346\211\276.java" | 27 +-- ...\346\250\241\350\277\220\347\256\227.java" | 9 +- ...\345\210\227\347\273\204\345\220\210.java" | 25 ++- ...\346\260\264\344\273\231\350\212\261.java" | 17 +- ...\346\261\202\345\205\224\345\255\220.java" | 15 +- .../advanced/java/annotation/AddMapper.java | 14 +- .../java/annotation/AnnotationTest.java | 7 +- .../advanced/java/annotation/Limit.java | 5 +- .../collections/CollectionsTest.java | 10 +- .../java/collection/list/ListTest.java | 2 +- .../advanced/java/collection/map/MapTest.java | 4 +- .../concurrency/CompletableFutureTest.java | 8 +- .../advanced/java/concurrency/UnsafeTest.java | 2 +- .../java/datastructure/IteratorElement.java | 8 +- .../advanced/java/datastructure/Position.java | 2 + .../java/datastructure/SparseArray.java | 22 +-- .../java/datastructure/deque/Deque.java | 10 +- .../java/datastructure/deque/LinkedDeque.java | 10 +- .../java/datastructure/deque/Node.java | 25 +-- .../java/datastructure/linked/Node.java | 23 ++- .../java/datastructure/list/List.java | 18 +- .../java/datastructure/list/NodeList.java | 13 +- .../java/datastructure/queue/LinkedQueue.java | 10 +- .../java/datastructure/queue/Queue.java | 7 +- .../java/datastructure/queue/QueueArray.java | 18 +- .../java/datastructure/queue/QueueTest.java | 2 +- .../java/datastructure/skiplist/SkipList.java | 149 +++++++++-------- .../datastructure/skiplist/SkipListNode.java | 21 ++- .../java/datastructure/stack/LinkedStack.java | 14 +- .../java/datastructure/stack/Stack.java | 6 +- .../java/datastructure/stack/StackArray.java | 19 ++- .../java/datastructure/stack/StackTest.java | 6 +- .../java/datastructure/tree/bin/BinTree.java | 26 ++- .../tree/bin/BinTreeLinkedList.java | 38 ++--- .../datastructure/tree/bin/BinTreeNode.java | 67 +++++--- .../tree/bin/BinTreePosition.java | 26 +++ .../tree/linked/IteratorTree.java | 15 +- .../java/datastructure/tree/linked/Tree.java | 11 +- .../tree/linked/TreeLinkedList.java | 22 ++- .../datastructure/vector/ArrayVector.java | 8 +- .../datastructure/vector/ExtArrayVector.java | 20 +-- .../java/datastructure/vector/Vector.java | 6 + .../java/datastructure/vector/VectorTest.java | 8 +- .../advanced/java/jvm/JvmParamTest.java | 60 +++---- .../factory/JettyWebServerFactory.java | 2 +- .../java/patterns/factory/ServerFactory.java | 34 ++-- .../factory/TomcatWebServerFactory.java | 5 +- .../java/patterns/factory/bean/Tomcat.java | 4 +- .../advanced/java/stream/StreamTest.java | 39 +++-- .../advanced/limiter/AutoIdempotent.java | 2 +- .../advanced/limiter/LimiterTokenService.java | 21 ++- .../limiter/LimiterTokenServiceImpl.java | 10 +- .../advanced/limiter/LocalCacheMap.java | 19 ++- .../advanced/mybatis/mapper/TestMapper.java | 9 +- .../javayh/advanced/spring/aop/SysLog.java | 1 + .../advanced/spring/aop/SysLogAspect.java | 53 +++--- .../javayh/advanced/spring/bean/BaseBean.java | 2 +- .../spring/bean/FactoryBeanLearn.java | 13 +- .../spring/transaction/TransactionTest.java | 4 +- .../spring/transaction/TransactionTest2.java | 4 +- .../javayh/advanced/spring/web/TestWeb.java | 4 +- .../com/javayh/advanced/util/UnsafeUtils.java | 7 +- .../main/resources/mapper/test/TestMapper.xml | 39 ++--- .../advanced/AdvancedApplicationTests.java | 2 +- .../javayh/advanced/spring/bean/BeanTest.java | 6 +- ...14\346\225\264\347\233\256\345\275\225.md" | 2 + 83 files changed, 972 insertions(+), 512 deletions(-) create mode 100644 note/java/concurrency/designpattern/ThreadPerMessage.md create mode 100644 note/java/concurrency/designpattern/WorkerThread.md create mode 100644 note/java/concurrency/designpattern/img/token.drawio diff --git a/note/actualCombat/Limiter.md b/note/actualCombat/Limiter.md index 92b28a2..da1e258 100644 --- a/note/actualCombat/Limiter.md +++ b/note/actualCombat/Limiter.md @@ -50,7 +50,7 @@ 针对前端重复连续多次点击的情况,例如恶意评论,支付,提交订单的接口就可以通过 Token 的机制实现防止重复提交。 - 流程图如下: -[token_limiter](img/token_limiter.png) +![token_limiter](img/token_limiter.png) 整个流程已经完成,但是我们在实际开发的时候还需要制定规则,来判断是否是重复提交 diff --git a/note/java/concurrency/README.md b/note/java/concurrency/README.md index 14127c7..d95d8da 100644 --- a/note/java/concurrency/README.md +++ b/note/java/concurrency/README.md @@ -12,3 +12,5 @@ - [线程本地存储模式:没有共享,就没有伤害](designpattern/ThreadLocalPattern.md) - [Guarded Suspension模式:等待唤醒机制的规范实现](designpattern/GuardedSuspension.md) - [Balking模式:再谈线程安全的单例模式](designpattern/Balking.md) +- [Thread-Per-Message模式:最简单实用的分工方法](designpattern/ThreadPerMessage.md) +- [Worker Thread模式:如何避免重复创建线程](designpattern/WorkerThread.md) diff --git a/note/java/concurrency/designpattern/ThreadPerMessage.md b/note/java/concurrency/designpattern/ThreadPerMessage.md new file mode 100644 index 0000000..0b8f242 --- /dev/null +++ b/note/java/concurrency/designpattern/ThreadPerMessage.md @@ -0,0 +1,156 @@ +## Thread-Per-Message模式:最简单实用的分工方法 + +我们曾经把并发编程领域的问题总结为三个核心问题:分工、同步和互斥。其中,同步和互斥相关问题更多地源自微观,而分工问题则是源自宏观。我们解决问题,往往都是从宏观入手,在编程领域,软件的设计过程也是先从概要设计开始,而后才进行详细设计。同样,解决并发编程问题,首要问题也是解决宏观的分工问题。 + +并发编程领域里,解决分工问题也有一系列的设计模式,比较常用的主要有 Thread-Per-Message 模式、Worker Thread 模式、生产者 - 消费者模式等等。今天我们重点介绍 Thread-Per-Message 模式。 + +### 如何理解 Thread-Per-Message 模式 + +现实世界里,很多事情我们都需要委托他人办理,一方面受限于我们的能力,总有很多搞不定的事,比如教育小朋友,搞不定怎么办呢?只能委托学校老师了;另一方面受限于我们的时间,比如忙着写 Bug,哪有时间买别墅呢?只能委托房产中介了。委托他人代办有一个非常大的好处,那就是可以专心做自己的事了。 + +在编程领域也有很多类似的需求,比如写一个 HTTP Server,很显然只能在主线程中接收请求,而不能处理 HTTP 请求,因为如果在主线程中处理 HTTP 请求的话,那同一时间只能处理一个请求,太慢了!怎么办呢?可以利用代办的思路,创建一个子线程,委托子线程去处理 HTTP 请求。 + +这种委托他人办理的方式,在并发编程领域被总结为一种设计模式,叫做 Thread-Per-Message 模式,简言之就是为每个任务分配一个独立的线程。这是一种最简单的分工方法,实现起来也非常简单。 + +### 用 Thread 实现 Thread-Per-Message 模式 + +Thread-Per-Message 模式的一个最经典的应用场景是网络编程里服务端的实现,服务端为每个客户端请求创建一个独立的线程,当线程处理完请求后,自动销毁,这是一种最简单的并发处理网络请求的方法。 + +网络编程里最简单的程序当数 echo 程序了,echo 程序的服务端会原封不动地将客户端的请求发送回客户端。例如,客户端发送 TCP 请求"Hello World",那么服务端也会返回"Hello World"。 + +下面我们就以 echo 程序的服务端为例,介绍如何实现 Thread-Per-Message 模式。 + +在 Java 语言中,实现 echo 程序的服务端还是很简单的。只需要 30 行代码就能够实现,示例代码如下,我们为每个请求都创建了一个 Java 线程,核心代码是:new Thread(()->{…}).start()。 + +```java + +final ServerSocketChannel ssc = + ServerSocketChannel.open().bind( + new InetSocketAddress(8080)); +//处理请求 +try { + while (true) { + // 接收请求 + SocketChannel sc = ssc.accept(); + // 每个请求都创建一个线程 + new Thread(()->{ + try { + // 读Socket + ByteBuffer rb = ByteBuffer + .allocateDirect(1024); + sc.read(rb); + //模拟处理请求 + Thread.sleep(2000); + // 写Socket + ByteBuffer wb = + (ByteBuffer)rb.flip(); + sc.write(wb); + // 关闭Socket + sc.close(); + }catch(Exception e){ + throw new UncheckedIOException(e); + } + }).start(); + } +} finally { + ssc.close(); +} +``` + +如果你熟悉网络编程,相信你一定会提出一个很尖锐的问题:上面这个 echo 服务的实现方案是不具备可行性的。原因在于 Java 中的线程是一个重量级的对象,创建成本很高,一方面创建线程比较耗时,另一方面线程占用的内存也比较大。所以,为每个请求创建一个新的线程并不适合高并发场景。 + +于是,你开始质疑 Thread-Per-Message 模式,而且开始重新思索解决方案,这时候很可能你会想到 Java 提供的线程池。你的这个思路没有问题,但是引入线程池难免会增加复杂度。其实你完全可以换一个角度来思考这个问题,语言、工具、框架本身应该是帮助我们更敏捷地实现方案的,而不是用来否定方案的,Thread-Per-Message 模式作为一种最简单的分工方案,Java 语言支持不了,显然是 Java 语言本身的问题。 + +Java 语言里,Java 线程是和操作系统线程一一对应的,这种做法本质上是将 Java 线程的调度权完全委托给操作系统,而操作系统在这方面非常成熟,所以这种做法的好处是稳定、可靠,但是也继承了操作系统线程的缺点:创建成本高。为了解决这个缺点,Java 并发包里提供了线程池等工具类。这个思路在很长一段时间里都是很稳妥的方案,但是这个方案并不是唯一的方案。 + +业界还有另外一种方案,叫做轻量级线程。这个方案在 Java 领域知名度并不高,但是在其他编程语言里却叫得很响,例如 Go 语言、Lua 语言里的协程,本质上就是一种轻量级的线程。轻量级的线程,创建的成本很低,基本上和创建一个普通对象的成本相似;并且创建的速度和内存占用相比操作系统线程至少有一个数量级的提升,所以基于轻量级线程实现 Thread-Per-Message 模式就完全没有问题了。 + +Java 语言目前也已经意识到轻量级线程的重要性了,OpenJDK 有个 Loom 项目,就是要解决 Java 语言的轻量级线程问题,在这个项目中,轻量级线程被叫做 Fiber。下面我们就来看看基于 Fiber 如何实现 Thread-Per-Message 模式。 + +### 用 Fiber 实现 Thread-Per-Message 模式 + +Loom 项目在设计轻量级线程时,充分考量了当前 Java 线程的使用方式,采取的是尽量兼容的态度,所以使用上还是挺简单的。用 Fiber 实现 echo 服务的示例代码如下所示,对比 Thread 的实现,你会发现改动量非常小,只需要把 new Thread(()->{…}).start() 换成 Fiber.schedule(()->{}) 就可以了。 + +```java + +final ServerSocketChannel ssc = + ServerSocketChannel.open().bind( + new InetSocketAddress(8080)); +//处理请求 +try{ + while (true) { + // 接收请求 + final SocketChannel sc = + serverSocketChannel.accept(); + Fiber.schedule(()->{ + try { + // 读Socket + ByteBuffer rb = ByteBuffer + .allocateDirect(1024); + sc.read(rb); + //模拟处理请求 + LockSupport.parkNanos(2000*1000000); + // 写Socket + ByteBuffer wb = + (ByteBuffer)rb.flip() + sc.write(wb); + // 关闭Socket + sc.close(); + } catch(Exception e){ + throw new UncheckedIOException(e); + } + }); + }//while +}finally{ + ssc.close(); +} +``` + +那使用 Fiber 实现的 echo 服务是否能够达到预期的效果呢?我们可以在 Linux 环境下做一个简单的实验,步骤如下: + +1. 首先通过 ulimit -u 512 将用户能创建的最大进程数(包括线程)设置为 512; +2. 启动 Fiber 实现的 echo 程序; +3. 利用压测工具 ab 进行压测:ab -r -c 20000 -n 200000 http:// 测试机 IP 地址:8080/ + +压测执行结果如下: + +```java + +Concurrency Level: 20000 +Time taken for tests: 67.718 seconds +Complete requests: 200000 +Failed requests: 0 +Write errors: 0 +Non-2xx responses: 200000 +Total transferred: 16400000 bytes +HTML transferred: 0 bytes +Requests per second: 2953.41 [#/sec] (mean) +Time per request: 6771.844 [ms] (mean) +Time per request: 0.339 [ms] (mean, across all concurrent requests) +Transfer rate: 236.50 [Kbytes/sec] received + +Connection Times (ms) + min mean[+/-sd] median max +Connect: 0 557 3541.6 1 63127 +Processing: 2000 2010 31.8 2003 2615 +Waiting: 1986 2008 30.9 2002 2615 +Total: 2000 2567 3543.9 2004 65293 +``` + +你会发现即便在 20000 并发下,该程序依然能够良好运行。同等条件下,Thread 实现的 echo 程序 512 并发都抗不过去,直接就 OOM 了。 + +如果你通过 Linux 命令 top -Hp pid 查看 Fiber 实现的 echo 程序的进程信息,你可以看到该进程仅仅创建了 16(不同 CPU 核数结果会不同)个操作系统线程。 + +![aebe9691be206fb88f45e4f763bcb7e9](img/aebe9691be206fb88f45e4f763bcb7e9.png) + +### 总结 + +并发编程领域的分工问题,指的是如何高效地拆解任务并分配给线程。前面我们在并发工具类模块中已经介绍了不少解决分工问题的工具类,例如 Future、CompletableFuture 、CompletionService、Fork/Join 计算框架等,这些工具类都能很好地解决特定应用场景的问题,所以,这些工具类曾经是 Java 语言引以为傲的。不过这些工具类都继承了 Java 语言的老毛病:太复杂。 + +如果你一直从事 Java 开发,估计你已经习以为常了,习惯性地认为这个复杂度是正常的。不过这个世界时刻都在变化,曾经正常的复杂度,现在看来也许就已经没有必要了,例如 Thread-Per-Message 模式如果使用线程池方案就会增加复杂度。 + +Thread-Per-Message 模式在 Java 领域并不是那么知名,根本原因在于 Java 语言里的线程是一个重量级的对象,为每一个任务创建一个线程成本太高,尤其是在高并发领域,基本就不具备可行性。不过这个背景条件目前正在发生巨变,Java 语言未来一定会提供轻量级线程,这样基于轻量级线程实现 Thread-Per-Message 模式就是一个非常靠谱的选择。 + +当然,对于一些并发度没那么高的异步场景,例如定时任务,采用 Thread-Per-Message 模式是完全没有问题的。实际工作中,我就见过完全基于 Thread-Per-Message 模式实现的分布式调度框架,这个框架为每个定时任务都分配了一个独立的线程。 + + diff --git a/note/java/concurrency/designpattern/WorkerThread.md b/note/java/concurrency/designpattern/WorkerThread.md new file mode 100644 index 0000000..4253351 --- /dev/null +++ b/note/java/concurrency/designpattern/WorkerThread.md @@ -0,0 +1,141 @@ +## Worker Thread模式:如何避免重复创建线程? + +在上一篇文章中,我们介绍了一种最简单的分工模式——Thread-Per-Message 模式,对应到现实世界,其实就是委托代办。这种分工模式如果用 Java Thread 实现,频繁地创建、销毁线程非常影响性能,同时无限制地创建线程还可能导致 OOM,所以在 Java 领域使用场景就受限了。 + +要想有效避免线程的频繁创建、销毁以及 OOM 问题,就不得不提今天我们要细聊的,也是 Java 领域使用最多的 Worker Thread 模式。 + +Worker Thread 模式及其实现 + +Worker Thread 模式可以类比现实世界里车间的工作模式:车间里的工人,有活儿了,大家一起干,没活儿了就聊聊天等着。你可以参考下面的示意图来理解,Worker Thread 模式中 Worker Thread 对应到现实世界里,其实指的就是车间里的工人。不过这里需要注意的是,车间里的工人数量往往是确定的。 + +![9d0082376427a97644ad7219af6922c3](img/9d0082376427a97644ad7219af6922c3.png) + +那在编程领域该如何模拟车间的这种工作模式呢?或者说如何去实现 Worker Thread 模式呢?通过上面的图,你很容易就能想到用阻塞队列做任务池,然后创建固定数量的线程消费阻塞队列中的任务。其实你仔细想会发现,这个方案就是 Java 语言提供的线程池。 + +线程池有很多优点,例如能够避免重复创建、销毁线程,同时能够限制创建线程的上限等等。学习完上一篇文章后你已经知道,用 Java 的 Thread 实现 Thread-Per-Message 模式难以应对高并发场景,原因就在于频繁创建、销毁 Java 线程的成本有点高,而且无限制地创建线程还可能导致应用 OOM。线程池,则恰好能解决这些问题。 + +那我们还是以 echo 程序为例,看看如何用线程池来实现。 + +下面的示例代码是用线程池实现的 echo 服务端,相比于 Thread-Per-Message 模式的实现,改动非常少,仅仅是创建了一个最多线程数为 500 的线程池 es,然后通过 es.execute() 方法将请求处理的任务提交给线程池处理。 + +```java + +ExecutorService es = Executors + .newFixedThreadPool(500); +final ServerSocketChannel ssc = + ServerSocketChannel.open().bind( + new InetSocketAddress(8080)); +//处理请求 +try { + while (true) { + // 接收请求 + SocketChannel sc = ssc.accept(); + // 将请求处理任务提交给线程池 + es.execute(()->{ + try { + // 读Socket + ByteBuffer rb = ByteBuffer + .allocateDirect(1024); + sc.read(rb); + //模拟处理请求 + Thread.sleep(2000); + // 写Socket + ByteBuffer wb = + (ByteBuffer)rb.flip(); + sc.write(wb); + // 关闭Socket + sc.close(); + }catch(Exception e){ + throw new UncheckedIOException(e); + } + }); + } +} finally { + ssc.close(); + es.shutdown(); +} +``` + +### 正确地创建线程池 + +Java 的线程池既能够避免无限制地创建线程导致 OOM,也能避免无限制地接收任务导致 OOM。只不过后者经常容易被我们忽略,例如在上面的实现中,就被我们忽略了。所以强烈建议你用创建有界的队列来接收任务。 + +当请求量大于有界队列的容量时,就需要合理地拒绝请求。如何合理地拒绝呢?这需要你结合具体的业务场景来制定,即便线程池默认的拒绝策略能够满足你的需求,也同样建议你在创建线程池时,清晰地指明拒绝策略。 + +同时,为了便于调试和诊断问题,我也强烈建议你在实际工作中给线程赋予一个业务相关的名字。 + +综合以上这三点建议,echo 程序中创建线程可以使用下面的示例代码。 + +```java + +ExecutorService es = new ThreadPoolExecutor( + 50, 500, + 60L, TimeUnit.SECONDS, + //注意要创建有界队列 + new LinkedBlockingQueue(2000), + //建议根据业务需求实现ThreadFactory + r->{ + return new Thread(r, "echo-"+ r.hashCode()); + }, + //建议根据业务需求实现RejectedExecutionHandler + new ThreadPoolExecutor.CallerRunsPolicy()); +``` + +### 避免线程死锁 + +使用线程池过程中,还要注意一种线程死锁的场景。如果提交到相同线程池的任务不是相互独立的,而是有依赖关系的,那么就有可能导致线程死锁。实际工作中,我就亲历过这种线程死锁的场景。具体现象是应用每运行一段时间偶尔就会处于无响应的状态,监控数据看上去一切都正常,但是实际上已经不能正常工作了。 + +这个出问题的应用,相关的逻辑精简之后,如下图所示,该应用将一个大型的计算任务分成两个阶段,第一个阶段的任务会等待第二阶段的子任务完成。在这个应用里,每一个阶段都使用了线程池,而且两个阶段使用的还是同一个线程池。 + +![](img/f807b0935133b315870d2d7db5477db8.png) + +我们可以用下面的示例代码来模拟该应用,如果你执行下面的这段代码,会发现它永远执行不到最后一行。执行过程中没有任何异常,但是应用已经停止响应了。 + +```java + +//L1、L2阶段共用的线程池 +ExecutorService es = Executors. + newFixedThreadPool(2); +//L1阶段的闭锁 +CountDownLatch l1=new CountDownLatch(2); +for (int i=0; i<2; i++){ + System.out.println("L1"); + //执行L1阶段任务 + es.execute(()->{ + //L2阶段的闭锁 + CountDownLatch l2=new CountDownLatch(2); + //执行L2阶段子任务 + for (int j=0; j<2; j++){ + es.execute(()->{ + System.out.println("L2"); + l2.countDown(); + }); + } + //等待L2阶段任务执行完 + l2.await(); + l1.countDown(); + }); +} +//等着L1阶段任务执行完 +l1.await(); +System.out.println("end"); +``` +当应用出现类似问题时,首选的诊断方法是查看线程栈。下图是上面示例代码停止响应后的线程栈,你会发现线程池中的两个线程全部都阻塞在 l2.await(); 这行代码上了,也就是说,线程池里所有的线程都在等待 L2 阶段的任务执行完,那 L2 阶段的子任务什么时候能够执行完呢?永远都没那一天了,为什么呢?因为线程池里的线程都阻塞了,没有空闲的线程执行 L2 阶段的任务了。 + +![](img/43c663eedd5b0b75b6c3022e26eb1583.png) + +原因找到了,那如何解决就简单了,最简单粗暴的办法就是将线程池的最大线程数调大,如果能够确定任务的数量不是非常多的话,这个办法也是可行的,否则这个办法就行不通了。其实这种问题通用的解决方案是为不同的任务创建不同的线程池。对于上面的这个应用,L1 阶段的任务和 L2 阶段的任务如果各自都有自己的线程池,就不会出现这种问题了。 + +最后再次强调一下:提交到相同线程池中的任务一定是相互独立的,否则就一定要慎重。 + +### 总结 + +我们曾经说过,解决并发编程里的分工问题,最好的办法是和现实世界做对比。对比现实世界构建编程领域的模型,能够让模型更容易理解。上一篇我们介绍的 Thread-Per-Message 模式,类似于现实世界里的委托他人办理,而今天介绍的 Worker Thread 模式则类似于车间里工人的工作模式。如果你在设计阶段,发现对业务模型建模之后,模型非常类似于车间的工作模式,那基本上就能确定可以在实现阶段采用 Worker Thread 模式来实现。 + +Worker Thread 模式和 Thread-Per-Message 模式的区别有哪些呢?从现实世界的角度看,你委托代办人做事,往往是和代办人直接沟通的;对应到编程领域,其实现也是主线程直接创建了一个子线程,主子线程之间是可以直接通信的。而车间工人的工作方式则是完全围绕任务展开的,一个具体的任务被哪个工人执行,预先是无法知道的;对应到编程领域,则是主线程提交任务到线程池,但主线程并不关心任务被哪个线程执行。 + +Worker Thread 模式能避免线程频繁创建、销毁的问题,而且能够限制线程的最大数量。Java 语言里可以直接使用线程池来实现 Worker Thread 模式,线程池是一个非常基础和优秀的工具类,甚至有些大厂的编码规范都不允许用 new Thread() 来创建线程的,必须使用线程池。 + +不过使用线程池还是需要格外谨慎的,除了今天重点讲到的如何正确创建线程池、如何避免线程死锁问题,还需要注意前面我们曾经提到的 ThreadLocal 内存泄露问题。同时对于提交到线程池的任务,还要做好异常处理,避免异常的任务从眼前溜走,从业务的角度看,有时没有发现异常的任务后果往往都很严重。 + + diff --git a/note/java/concurrency/designpattern/img/token.drawio b/note/java/concurrency/designpattern/img/token.drawio new file mode 100644 index 0000000..b025fbc --- /dev/null +++ b/note/java/concurrency/designpattern/img/token.drawio @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source-code/src/main/java/com/javayh/advanced/AdvancedApplication.java b/source-code/src/main/java/com/javayh/advanced/AdvancedApplication.java index 2de20bf..45bb6ef 100644 --- a/source-code/src/main/java/com/javayh/advanced/AdvancedApplication.java +++ b/source-code/src/main/java/com/javayh/advanced/AdvancedApplication.java @@ -9,8 +9,9 @@ *

* *

- * @version 1.0.0 + * * @author Dylan-haiji + * @version 1.0.0 */ @Slf4j @SpringBootApplication @@ -20,7 +21,7 @@ public class AdvancedApplication { public AdvancedApplication(CustomConfigurationProperties customConfigurationProperties) { this.customConfigurationProperties = customConfigurationProperties; - log.info("customConfigurationProperties init : {}",customConfigurationProperties.toString()); + log.info("customConfigurationProperties init : {}", customConfigurationProperties.toString()); } public static void main(String[] args) { diff --git a/source-code/src/main/java/com/javayh/advanced/config/AutoIdempotentInterceptor.java b/source-code/src/main/java/com/javayh/advanced/config/AutoIdempotentInterceptor.java index 569d783..6921157 100644 --- a/source-code/src/main/java/com/javayh/advanced/config/AutoIdempotentInterceptor.java +++ b/source-code/src/main/java/com/javayh/advanced/config/AutoIdempotentInterceptor.java @@ -27,21 +27,21 @@ public class AutoIdempotentInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - if(!(handler instanceof HandlerMethod)) { + if (!(handler instanceof HandlerMethod)) { return true; } HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); //被ApiIdempotment标记的扫描 AutoIdempotent methodAnnotation = method.getAnnotation(AutoIdempotent.class); - if(methodAnnotation != null) { - try{ + if (methodAnnotation != null) { + try { long time = methodAnnotation.time(); String token = request.getParameter("token"); // 幂等性校验, 校验通过则放行, 校验失败则抛出异常, 并通过统一异常处理返回友好提示 - return limiterTokenService.checkToken(token,time); + return limiterTokenService.checkToken(token, time); - }catch(Exception ex){ + } catch (Exception ex) { throw ex; } } diff --git a/source-code/src/main/java/com/javayh/advanced/config/WebConfiguration.java b/source-code/src/main/java/com/javayh/advanced/config/WebConfiguration.java index 4733162..400cd26 100644 --- a/source-code/src/main/java/com/javayh/advanced/config/WebConfiguration.java +++ b/source-code/src/main/java/com/javayh/advanced/config/WebConfiguration.java @@ -23,6 +23,7 @@ public class WebConfiguration implements WebMvcConfigurer { /** * 添加拦截器 + * * @param registry */ @Override diff --git a/source-code/src/main/java/com/javayh/advanced/exception/ExceptionBoundaryViolation.java b/source-code/src/main/java/com/javayh/advanced/exception/ExceptionBoundaryViolation.java index 03f620c..39da60d 100644 --- a/source-code/src/main/java/com/javayh/advanced/exception/ExceptionBoundaryViolation.java +++ b/source-code/src/main/java/com/javayh/advanced/exception/ExceptionBoundaryViolation.java @@ -9,7 +9,7 @@ * @version 1.0.0 * @since 2020-08-22 */ -public class ExceptionBoundaryViolation extends RuntimeException{ +public class ExceptionBoundaryViolation extends RuntimeException { public ExceptionBoundaryViolation(String message) { super(message); diff --git a/source-code/src/main/java/com/javayh/advanced/exception/ExceptionPositionInvalid.java b/source-code/src/main/java/com/javayh/advanced/exception/ExceptionPositionInvalid.java index 6d0bc2c..39cdb6f 100644 --- a/source-code/src/main/java/com/javayh/advanced/exception/ExceptionPositionInvalid.java +++ b/source-code/src/main/java/com/javayh/advanced/exception/ExceptionPositionInvalid.java @@ -9,7 +9,7 @@ * @version 1.0.0 * @since 2020-08-25 */ -public class ExceptionPositionInvalid extends RuntimeException{ +public class ExceptionPositionInvalid extends RuntimeException { public ExceptionPositionInvalid(String message) { super(message); } diff --git a/source-code/src/main/java/com/javayh/advanced/exception/ExceptionStackEmpty.java b/source-code/src/main/java/com/javayh/advanced/exception/ExceptionStackEmpty.java index a57ad9e..9692ee3 100644 --- a/source-code/src/main/java/com/javayh/advanced/exception/ExceptionStackEmpty.java +++ b/source-code/src/main/java/com/javayh/advanced/exception/ExceptionStackEmpty.java @@ -2,14 +2,14 @@ /** *

- * ExceptionStackEmpty + * ExceptionStackEmpty *

* * @author hai ji * @version 1.0.0 * @since 2020-08-19 */ -public class ExceptionStackEmpty extends RuntimeException{ +public class ExceptionStackEmpty extends RuntimeException { public ExceptionStackEmpty(String message) { super(message); diff --git a/source-code/src/main/java/com/javayh/advanced/exception/ExceptionStackFull.java b/source-code/src/main/java/com/javayh/advanced/exception/ExceptionStackFull.java index 1220491..34f1ec1 100644 --- a/source-code/src/main/java/com/javayh/advanced/exception/ExceptionStackFull.java +++ b/source-code/src/main/java/com/javayh/advanced/exception/ExceptionStackFull.java @@ -9,7 +9,7 @@ * @version 1.0.0 * @since 2020-08-19 */ -public class ExceptionStackFull extends RuntimeException{ +public class ExceptionStackFull extends RuntimeException { public ExceptionStackFull(String message) { super(message); diff --git a/source-code/src/main/java/com/javayh/advanced/exception/ServerException.java b/source-code/src/main/java/com/javayh/advanced/exception/ServerException.java index 0245af2..79bd963 100644 --- a/source-code/src/main/java/com/javayh/advanced/exception/ServerException.java +++ b/source-code/src/main/java/com/javayh/advanced/exception/ServerException.java @@ -9,7 +9,7 @@ * @version 1.0.0 * @since 2020-09-14 */ -public class ServerException extends Exception{ +public class ServerException extends Exception { public ServerException(String message) { super(message); diff --git a/source-code/src/main/java/com/javayh/advanced/java/ExamplesEnum/ExamplesEnum.java b/source-code/src/main/java/com/javayh/advanced/java/ExamplesEnum/ExamplesEnum.java index 588a5b6..081c8bf 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/ExamplesEnum/ExamplesEnum.java +++ b/source-code/src/main/java/com/javayh/advanced/java/ExamplesEnum/ExamplesEnum.java @@ -69,24 +69,26 @@ enum Day2 { /** * 私有构造,防止被外部调用 */ - private Day2(String desc,Integer code) { + private Day2(String desc, Integer code) { this.desc = desc; this.code = code; } /** * 定义方法,返回描述,跟常规类的定义没区别 + * * @return */ public String getDesc() { return desc; } + public int getCode() { return code; } - public String getDesc(int index){ - for (Day2 day2 : Day2.values()){ + public String getDesc(int index) { + for (Day2 day2 : Day2.values()) { if (day2.code == index) { return day2.desc; } @@ -94,8 +96,8 @@ public String getDesc(int index){ return null; } - public int getCode(String desc){ - for (Day2 day2 : Day2.values()){ + public int getCode(String desc) { + for (Day2 day2 : Day2.values()) { if (Objects.equals(day2.desc, desc)) { return day2.code; } diff --git "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/sort/\345\206\222\346\263\241\346\216\222\345\272\217.java" "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/sort/\345\206\222\346\263\241\346\216\222\345\272\217.java" index 7011d43..d6846c9 100644 --- "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/sort/\345\206\222\346\263\241\346\216\222\345\272\217.java" +++ "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/sort/\345\206\222\346\263\241\346\216\222\345\272\217.java" @@ -14,13 +14,13 @@ public class 冒泡排序 { public static void main(String[] args) { - int[] array = new int[]{2,10,8,12,5,1,89}; + int[] array = new int[]{2, 10, 8, 12, 5, 1, 89}; //暂存值 int temp = 0; //控制循环的次数 - for (int i = 0; i < array.length-1; i++) { + for (int i = 0; i < array.length - 1; i++) { //进行重排序 这里 array.length-1-i 减少循环次数 - for (int j = 0; j < array.length-1-i; j++) { + for (int j = 0; j < array.length - 1 - i; j++) { if (array[j] > array[j + 1]) { temp = array[j]; //调换前后位置 @@ -29,6 +29,6 @@ public static void main(String[] args) { } } } - System.out.println("排序后的数据:"+ Arrays.toString(array)); + System.out.println("排序后的数据:" + Arrays.toString(array)); } } diff --git "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/sort/\346\217\222\345\205\245\346\216\222\345\272\217.java" "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/sort/\346\217\222\345\205\245\346\216\222\345\272\217.java" index 6054bcf..e739665 100644 --- "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/sort/\346\217\222\345\205\245\346\216\222\345\272\217.java" +++ "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/sort/\346\217\222\345\205\245\346\216\222\345\272\217.java" @@ -15,6 +15,7 @@ public class 插入排序 { private static final int[] array = {49, 38, 65, 97, 76, 13, 27, 78, 34, 12, 15, 35, 25, 53, 51}; + public static void main(String[] args) { for (int i = 1; i < array.length; i++) { int temp = array[i]; diff --git "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\344\270\244\346\225\260\347\233\270\345\212\240.java" "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\344\270\244\346\225\260\347\233\270\345\212\240.java" index e429efc..ec01d7e 100644 --- "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\344\270\244\346\225\260\347\233\270\345\212\240.java" +++ "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\344\270\244\346\225\260\347\233\270\345\212\240.java" @@ -24,19 +24,19 @@ public static void main(String[] args) { ListNode listNode1 = new ListNode(2); ListNode listNode2 = new ListNode(4); ListNode listNode3 = new ListNode(3); - listNode1.next =listNode2; + listNode1.next = listNode2; listNode2.next = listNode3; ListNode list1 = new ListNode(5); ListNode list2 = new ListNode(6); ListNode list3 = new ListNode(4); - list1.next =list2; + list1.next = list2; list2.next = list3; - addTwoNumbers(listNode1,list1); + addTwoNumbers(listNode1, list1); } public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { - System.out.println("输出l1:"+l1.val+"->"+l1.next.val+"->"+l1.next.next.val); - System.out.println("输出l2:"+l2.val+"->"+l2.next.val+"->"+l2.next.next.val); + System.out.println("输出l1:" + l1.val + "->" + l1.next.val + "->" + l1.next.next.val); + System.out.println("输出l2:" + l2.val + "->" + l2.next.val + "->" + l2.next.next.val); ListNode dummyHead = new ListNode(0); ListNode p = l1, q = l2, curr = dummyHead; int carry = 0; @@ -62,8 +62,12 @@ public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { } + class ListNode { int val; ListNode next; - ListNode(int x) { val = x; } + + ListNode(int x) { + val = x; + } } diff --git "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\344\272\214\345\210\206\346\237\245\346\211\276.java" "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\344\272\214\345\210\206\346\237\245\346\211\276.java" index 23cad35..91b3f89 100644 --- "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\344\272\214\345\210\206\346\237\245\346\211\276.java" +++ "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\344\272\214\345\210\206\346\237\245\346\211\276.java" @@ -11,29 +11,30 @@ */ public class 二分查找 { public static void main(String[] args) { - int array[] = {3,5,11,17,21,23,28,30,32,50,64,78,81,95,101}; - System.out.println(binSerch(array,5,array.length-1,81)); + int array[] = {3, 5, 11, 17, 21, 23, 28, 30, 32, 50, 64, 78, 81, 95, 101}; + System.out.println(binSerch(array, 5, array.length - 1, 81)); } /** - * 递归实现 - * @param art 数组 + * 递归实现 + * + * @param art 数组 * @param start 开始下标 * @param end 结束下标 - * @param key 需要查找的数值 + * @param key 需要查找的数值 * @return */ - public static int binSerch(int art[],int start,int end ,int key){ - int mid = (end + start)/2; - if (art[mid] == key){ + public static int binSerch(int art[], int start, int end, int key) { + int mid = (end + start) / 2; + if (art[mid] == key) { return mid; } - if (start >= end){ + if (start >= end) { return -1; - }else if(key > art[mid]){ - return binSerch(art,mid+1,end,key); - }else if(key < art[mid]){ - return binSerch(art,start,mid-1,key); + } else if (key > art[mid]) { + return binSerch(art, mid + 1, end, key); + } else if (key < art[mid]) { + return binSerch(art, start, mid - 1, key); } return -1; } diff --git "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\345\217\226\346\250\241\350\277\220\347\256\227.java" "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\345\217\226\346\250\241\350\277\220\347\256\227.java" index c1bf354..d0eeec8 100644 --- "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\345\217\226\346\250\241\350\277\220\347\256\227.java" +++ "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\345\217\226\346\250\241\350\277\220\347\256\227.java" @@ -15,14 +15,15 @@ public class 取模运算 { public static void main(String[] args) { // 判断1-20之间有多少个素数,并输出所有素数 // 不能被2整除的数 - System.out.println("个数:"+mouldTaking(20)); + System.out.println("个数:" + mouldTaking(20)); } - static int mouldTaking(Integer num){ + + static int mouldTaking(Integer num) { AtomicInteger sum = new AtomicInteger(0); for (int i = 1; i < num; i++) { - if(i % 2 !=0){ - System.out.println("素数:"+i); + if (i % 2 != 0) { + System.out.println("素数:" + i); sum.incrementAndGet(); } } diff --git "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\346\216\222\345\210\227\347\273\204\345\220\210.java" "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\346\216\222\345\210\227\347\273\204\345\220\210.java" index 4f56f65..982009e 100644 --- "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\346\216\222\345\210\227\347\273\204\345\220\210.java" +++ "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\346\216\222\345\210\227\347\273\204\345\220\210.java" @@ -14,18 +14,19 @@ public class 排列组合 { public static void main(String[] args) { - arrangementSelect(new String[] { + arrangementSelect(new String[]{ "1", "2", "3", "4" }, 2); - combinationSelect(new String[] { + combinationSelect(new String[]{ "1", "2", "3", "4", "5" }, 3); } /** * 排列选择(从列表中选择n个排列) + * * @param dataList 待选列表 - * @param n 选择个数 + * @param n 选择个数 */ public static void arrangementSelect(String[] dataList, int n) { System.out.println(String.format("A(%d, %d) = %d", dataList.length, n, arrangement(dataList.length, n))); @@ -34,8 +35,9 @@ public static void arrangementSelect(String[] dataList, int n) { /** * 排列选择 - * @param dataList 待选列表 - * @param resultList 前面(resultIndex-1)个的排列结果 + * + * @param dataList 待选列表 + * @param resultList 前面(resultIndex-1)个的排列结果 * @param resultIndex 选择索引,从0开始 */ private static void arrangementSelect(String[] dataList, String[] resultList, int resultIndex) { @@ -64,8 +66,9 @@ private static void arrangementSelect(String[] dataList, String[] resultList, in /** * 组合选择(从列表中选择n个组合) + * * @param dataList 待选列表 - * @param n 选择个数 + * @param n 选择个数 */ public static void combinationSelect(String[] dataList, int n) { System.out.println(String.format("C(%d, %d) = %d", dataList.length, n, combination(dataList.length, n))); @@ -74,9 +77,10 @@ public static void combinationSelect(String[] dataList, int n) { /** * 组合选择 - * @param dataList 待选列表 - * @param dataIndex 待选开始索引 - * @param resultList 前面(resultIndex-1)个的组合结果 + * + * @param dataList 待选列表 + * @param dataIndex 待选开始索引 + * @param resultList 前面(resultIndex-1)个的组合结果 * @param resultIndex 选择索引,从0开始 */ private static void combinationSelect(String[] dataList, int dataIndex, String[] resultList, int resultIndex) { @@ -96,6 +100,7 @@ private static void combinationSelect(String[] dataList, int dataIndex, String[] /** * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1 + * * @param n * @return */ @@ -105,6 +110,7 @@ public static long factorial(int n) { /** * 计算排列数,即A(n, m) = n!/(n-m)! + * * @param n * @param m * @return @@ -115,6 +121,7 @@ public static long arrangement(int n, int m) { /** * 计算组合数,即C(n, m) = n!/((n-m)! * m!) + * * @param n * @param m * @return diff --git "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\346\260\264\344\273\231\350\212\261.java" "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\346\260\264\344\273\231\350\212\261.java" index 5af584e..b06cefd 100644 --- "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\346\260\264\344\273\231\350\212\261.java" +++ "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\346\260\264\344\273\231\350\212\261.java" @@ -14,31 +14,30 @@ public static void main(String[] args) { //打印出所有的 "水仙花数 ",所谓 "水仙花数 "是指一个三位数,其各位数字立方和等于该数本身。 // 例如:153是一个 "水仙花数 ",因为153=1的三次方+5的三次方+3的三次方。 System.out.println(narcissus(153, 3)); - System.out.println(narcissus(370 , 3)); - System.out.println(narcissus(407 , 3)); + System.out.println(narcissus(370, 3)); + System.out.println(narcissus(407, 3)); System.out.println(narcissus(371, 3)); System.out.println(narcissus(334, 3)); } /** - * * @param num 原数据 * @param pow 次方数 * @return */ - static boolean narcissus(Integer num, Integer pow){ - int x , y , z = 0; + static boolean narcissus(Integer num, Integer pow) { + int x, y, z = 0; //计算出十位与各位的数 int ten = num % 100; //计算出百位 x = num / 100; //计算出十位 - y = ten/10; + y = ten / 10; //计算出各位 z = ten % 10; - int sum = (int) (Math.pow(x,pow) + Math.pow(y,pow) + Math.pow(z,pow)); - System.out.println("计算前的数据:"+num); - System.out.println("计算水仙花数的和为:"+sum); + int sum = (int) (Math.pow(x, pow) + Math.pow(y, pow) + Math.pow(z, pow)); + System.out.println("计算前的数据:" + num); + System.out.println("计算水仙花数的和为:" + sum); return sum == num; } } diff --git "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\347\256\227\346\263\225\344\271\213\351\200\222\345\275\222\346\261\202\345\205\224\345\255\220.java" "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\347\256\227\346\263\225\344\271\213\351\200\222\345\275\222\346\261\202\345\205\224\345\255\220.java" index 85dc938..86c9ea6 100644 --- "a/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\347\256\227\346\263\225\344\271\213\351\200\222\345\275\222\346\261\202\345\205\224\345\255\220.java" +++ "b/source-code/src/main/java/com/javayh/advanced/java/algorithm/example/\347\256\227\346\263\225\344\271\213\351\200\222\345\275\222\346\261\202\345\205\224\345\255\220.java" @@ -14,13 +14,13 @@ public class 算法之递归求兔子 { /** * 有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第3个月后每个月又生一对兔子, * 假如兔子都不死,问每个月的兔子总数为多少? - * - * 分析 - * 1 2 3 4 5 6 7 + *

+ * 分析 + * 1 2 3 4 5 6 7 * 种兔 1 1 1 1 2 3 5 * 小兔 0 0 1 2 3 5 8 * 总数 1 1 2 3 5 8 13 - * 当月的总数 = 前两个月的和 + * 当月的总数 = 前两个月的和 */ public static void main(String[] args) { for (int i = 0; i < 12; i++) { @@ -30,15 +30,16 @@ public static void main(String[] args) { /** * 求和 + * * @param mo * @return */ - static int sum(int mo){ + static int sum(int mo) { //前两个月没有幼兔产生 - if(1 == mo || 2 == mo){ + if (1 == mo || 2 == mo) { return 1; } - return sum(mo - 1) + sum(mo -2); + return sum(mo - 1) + sum(mo - 2); } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/annotation/AddMapper.java b/source-code/src/main/java/com/javayh/advanced/java/annotation/AddMapper.java index 4310eb3..d15db8b 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/annotation/AddMapper.java +++ b/source-code/src/main/java/com/javayh/advanced/java/annotation/AddMapper.java @@ -9,22 +9,18 @@ * @version 1.0.0 * @since 2020-07-17 */ -public class AddMapper -{ +public class AddMapper { - @Limit(value ="Test") - public void test() - { + @Limit(value = "Test") + public void test() { System.out.println("test case"); } - public void additional() - { + public void additional() { System.out.println("additional test case"); } - private void add() - { + private void add() { System.out.println("add test case"); } diff --git a/source-code/src/main/java/com/javayh/advanced/java/annotation/AnnotationTest.java b/source-code/src/main/java/com/javayh/advanced/java/annotation/AnnotationTest.java index 520eba9..932a6cd 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/annotation/AnnotationTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/annotation/AnnotationTest.java @@ -16,8 +16,7 @@ * @version 1.0.0 * @since 2020-07-17 */ -public class AnnotationTest -{ +public class AnnotationTest { private static final Logger logger = LoggerFactory.getLogger(AnnotationTest.class); public static void main(String[] args) { @@ -33,13 +32,13 @@ public static void main(String[] args) { //获取注解 Limit annotation = method.getAnnotation(Limit.class); String value = annotation.value(); - if(Strings.isBlank(value)){ + if (Strings.isBlank(value)) { value = "Limit"; } method.invoke(addMapper); } catch (IllegalAccessException | InvocationTargetException e) { logger.error( - "IllegalAccessException | InvocationTargetException---> {}",e.getMessage()); + "IllegalAccessException | InvocationTargetException---> {}", e.getMessage()); } } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/annotation/Limit.java b/source-code/src/main/java/com/javayh/advanced/java/annotation/Limit.java index 498ee49..63c0f14 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/annotation/Limit.java +++ b/source-code/src/main/java/com/javayh/advanced/java/annotation/Limit.java @@ -16,10 +16,9 @@ * @since 2020-07-17 */ @Documented -@Target(value= {ElementType.METHOD}) +@Target(value = {ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) -public @interface Limit -{ +public @interface Limit { String value(); } diff --git a/source-code/src/main/java/com/javayh/advanced/java/collection/collections/CollectionsTest.java b/source-code/src/main/java/com/javayh/advanced/java/collection/collections/CollectionsTest.java index 4e59a6d..abb6aaf 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/collection/collections/CollectionsTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/collection/collections/CollectionsTest.java @@ -17,21 +17,21 @@ public class CollectionsTest { public static void main(String[] args) { List listOne = new ArrayList<>(); - String[] strings = new String[]{"List","Set","Map"}; - Collections.addAll(listOne,"Yang","Hai","ji"); - Collections.addAll(listOne,strings); + String[] strings = new String[]{"List", "Set", "Map"}; + Collections.addAll(listOne, "Yang", "Hai", "ji"); + Collections.addAll(listOne, strings); System.out.println(listOne); List listTwo = new ArrayList<>(); for (int i = 0; i < 1000; i++) { - listTwo.add("Yang"+i); + listTwo.add("Yang" + i); } int yang999 = Collections.binarySearch(listTwo, "Yang999"); System.out.println(yang999); List linkedList = new LinkedList<>(); for (int i = 0; i < 5050; i++) { - linkedList.add("Hai"+i); + linkedList.add("Hai" + i); } int hai = Collections.binarySearch(linkedList, "Hai999"); System.out.println(hai); diff --git a/source-code/src/main/java/com/javayh/advanced/java/collection/list/ListTest.java b/source-code/src/main/java/com/javayh/advanced/java/collection/list/ListTest.java index cc963cb..9bfc027 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/collection/list/ListTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/collection/list/ListTest.java @@ -5,7 +5,7 @@ /** *

- * list test case + * list test case *

* * @author Dylan-haiji diff --git a/source-code/src/main/java/com/javayh/advanced/java/collection/map/MapTest.java b/source-code/src/main/java/com/javayh/advanced/java/collection/map/MapTest.java index 860cd52..8f8a729 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/collection/map/MapTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/collection/map/MapTest.java @@ -15,9 +15,9 @@ public class MapTest { public static void main(String[] args) { - Map map = new HashMap<>(8, 0.75f); + Map map = new HashMap<>(8, 0.75f); for (int i = 0; i < 15; i++) { - map.put(i+"java",i+"java"); + map.put(i + "java", i + "java"); } } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/concurrency/CompletableFutureTest.java b/source-code/src/main/java/com/javayh/advanced/java/concurrency/CompletableFutureTest.java index f99c470..5fc2460 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/concurrency/CompletableFutureTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/concurrency/CompletableFutureTest.java @@ -17,7 +17,7 @@ public class CompletableFutureTest { public static void main(String[] args) { //任务1:洗水壶->烧开水 CompletableFuture f1 = - CompletableFuture.runAsync(()->{ + CompletableFuture.runAsync(() -> { System.out.println("T1:洗水壶..."); sleep(1, TimeUnit.SECONDS); @@ -26,7 +26,7 @@ public static void main(String[] args) { }); //任务2:洗茶壶->洗茶杯->拿茶叶 CompletableFuture f2 = - CompletableFuture.supplyAsync(()->{ + CompletableFuture.supplyAsync(() -> { System.out.println("T2:洗茶壶..."); sleep(1, TimeUnit.SECONDS); @@ -39,7 +39,7 @@ public static void main(String[] args) { }); //任务3:任务1和任务2完成后执行:泡茶 CompletableFuture f3 = - f1.thenCombine(f2, (aVoid, tf)->{ + f1.thenCombine(f2, (aVoid, tf) -> { System.out.println("T1:拿到茶叶:" + tf); System.out.println("T1:泡茶..."); return "上茶:" + tf; @@ -53,7 +53,7 @@ public static void main(String[] args) { static void sleep(int t, TimeUnit u) { try { u.sleep(t); - }catch(InterruptedException e){ + } catch (InterruptedException e) { e.printStackTrace(); } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/concurrency/UnsafeTest.java b/source-code/src/main/java/com/javayh/advanced/java/concurrency/UnsafeTest.java index d4b89dd..75a6f25 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/concurrency/UnsafeTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/concurrency/UnsafeTest.java @@ -11,7 +11,7 @@ /** *

- * 测试 Unsafe + * 测试 Unsafe *

* * @author hai ji diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/IteratorElement.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/IteratorElement.java index ec876ba..e9763e7 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/IteratorElement.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/IteratorElement.java @@ -12,12 +12,16 @@ * @version 1.0.0 * @since 2020-09-09 */ -public class IteratorElement implements Iterator { +public class IteratorElement implements Iterator { private List list;//列表 private Position nextPosition;//当前(下一个)元素的位置 + //默认构造方法 - public IteratorElement() { list = null; } + public IteratorElement() { + list = null; + } + //构造方法 public IteratorElement(List L) { list = L; diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/Position.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/Position.java index 974ec37..668dc52 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/Position.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/Position.java @@ -13,12 +13,14 @@ public interface Position { /** * 获取元素 + * * @return */ E getElem(); /** * 将给定元素存放至该位置,返回此前存放的元素 + * * @param e 插入元素 * @return */ diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/SparseArray.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/SparseArray.java index dc89df4..03f54b8 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/SparseArray.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/SparseArray.java @@ -2,7 +2,7 @@ /** *

- * 稀疏数组 + * 稀疏数组 *

* * @author hai ji @@ -15,13 +15,13 @@ public static void main(String[] args) { //1. 创建一个二维数组 int[][] array1 = new int[11][11]; - array1[1][2]=1; - array1[2][3]=2; + array1[1][2] = 1; + array1[2][3] = 2; //2. 输出原始数组 System.out.println("---原始二维数组---"); for (int[] row : array1) { for (int data : row) { - System.out.printf("%d\t",data); + System.out.printf("%d\t", data); }//换行 System.out.println(); } @@ -42,14 +42,14 @@ public static void main(String[] args) { //3.2 创建稀疏数组 int[][] sparseArray = new int[sum + 1][3]; // 初始化稀疏数组 第一行 - sparseArray[0][0]= array1.length; - sparseArray[0][1]=array1.length; - sparseArray[0][2]=sum; + sparseArray[0][0] = array1.length; + sparseArray[0][1] = array1.length; + sparseArray[0][2] = sum; int count = 0; for (int i = 0; i < array1.length; i++) { for (int j = 0; j < array1.length; j++) { - if (array1[i][j]!=0){ + if (array1[i][j] != 0) { count++; sparseArray[count][0] = i; sparseArray[count][1] = j; @@ -74,9 +74,9 @@ public static void main(String[] args) { array2[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2]; } System.out.println("恢复后的二维数组"); - for (int[] row: array2){ - for(int data : row){ - System.out.printf("%d\t",data); + for (int[] row : array2) { + for (int data : row) { + System.out.printf("%d\t", data); } System.out.println(); } diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/Deque.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/Deque.java index e1bda72..e1d95f6 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/Deque.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/Deque.java @@ -4,7 +4,7 @@ /** *

- * 自定义双端队列接口 + * 自定义双端队列接口 *

* * @author hai ji @@ -14,18 +14,21 @@ public interface Deque { /** * 返回队列中元素数目 + * * @return */ int size(); /** * 判断队列是否为空 + * * @return */ boolean isEmpty(); /** * 取首元素(但不删除) + * * @return * @throws ExceptionQueueEmpty */ @@ -33,6 +36,7 @@ public interface Deque { /** * 取末元素(但不删除) + * * @return * @throws ExceptionQueueEmpty */ @@ -40,18 +44,21 @@ public interface Deque { /** * 将新元素作为首元素插入 + * * @param obj */ void addFirst(E obj); /** * 将新元素作为末元素插入 + * * @param obj */ void aadLast(E obj); /** * 删除首元素 + * * @return * @throws ExceptionQueueEmpty */ @@ -59,6 +66,7 @@ public interface Deque { /** * 删除末元素 + * * @return * @throws ExceptionQueueEmpty */ diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/LinkedDeque.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/LinkedDeque.java index 4207bb2..c9f3a38 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/LinkedDeque.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/LinkedDeque.java @@ -4,14 +4,14 @@ /** *

- * 自定义双端队列 + * 自定义双端队列 *

* * @author hai ji * @version 1.0.0 * @since 2020-08-21 */ -public class LinkedDeque implements Deque{ +public class LinkedDeque implements Deque { //指向头节点(哨兵) protected Node header; @@ -40,7 +40,7 @@ public boolean isEmpty() { @Override public E first() throws ExceptionQueueEmpty { - if (isEmpty()){ + if (isEmpty()) { throw new ExceptionQueueEmpty("意外:双端队列为空"); } return header.getNext().getElem(); @@ -48,7 +48,7 @@ public E first() throws ExceptionQueueEmpty { @Override public E last() throws ExceptionQueueEmpty { - if (isEmpty()){ + if (isEmpty()) { throw new ExceptionQueueEmpty("意外:双端队列为空"); } return trailer.getPrev().getElem(); @@ -104,7 +104,7 @@ public E removeLast() throws ExceptionQueueEmpty { public void iterator() { Node p = header.getNext(); while (p != trailer) { - System.out.print(p.getElem()+" "); + System.out.print(p.getElem() + " "); p = p.getNext(); } System.out.println(); diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/Node.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/Node.java index 57a98b5..f6969ff 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/Node.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/deque/Node.java @@ -20,17 +20,17 @@ public class Node implements Position { private Node next; public Node() { - this(null,null,null); + this(null, null, null); } /** - * 注意三个参数的次序:数据对象、前驱节点、后继节点 + * 注意三个参数的次序:数据对象、前驱节点、后继节点 + * * @param e 数据对象 * @param p 前驱节点 * @param n 后继节点 */ - public Node(E e, Node p, Node n) - { + public Node(E e, Node p, Node n) { element = e; prev = p; next = n; @@ -44,6 +44,7 @@ public E getElem() { /** * 将给定的元素放入该位置,并返回原来的元素 + * * @param e 插入元素 * @return */ @@ -56,37 +57,37 @@ public E setElem(E e) { /** * 找到后继位置 + * * @return */ - public Node getNext() - { + public Node getNext() { return next; } /** * 找到前驱位置 + * * @return */ - public Node getPrev() - { + public Node getPrev() { return prev; } /** * 修改后继位置 + * * @param newNext */ - public void setNext(Node newNext) - { + public void setNext(Node newNext) { next = newNext; } /** * 修改前驱位置 + * * @param newPrev */ - public void setPrev(Node newPrev) - { + public void setPrev(Node newPrev) { prev = newPrev; } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/linked/Node.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/linked/Node.java index 69a2510..894945e 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/linked/Node.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/linked/Node.java @@ -4,7 +4,7 @@ /** *

- * 单链表节点 + * 单链表节点 *

* * @author hai ji @@ -20,32 +20,29 @@ public class Node implements Position { /** * 指向数据对象、后继节点的引用都置空 */ - public Node() - { + public Node() { this(null, null); } /** * 指定数据对象及后继节点 + * * @param e * @param n */ - public Node(E e, Node n) - { + public Node(E e, Node n) { element = e; next = n; } @Override - public E getElem() - { + public E getElem() { return element; } @Override - public E setElem(E e) - { + public E setElem(E e) { E oldElem = element; element = e; return oldElem; @@ -53,19 +50,19 @@ public E setElem(E e) /** * 取当前节点的后继节点 + * * @return */ - public Node getNext() - { + public Node getNext() { return next; } /** * 修改当前节点的后继节点 + * * @param newNext */ - public void setNext(Node newNext) - { + public void setNext(Node newNext) { next = newNext; } diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/list/List.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/list/List.java index e7f1a48..6815b6d 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/list/List.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/list/List.java @@ -7,7 +7,7 @@ /** *

- * 自定义列表 + * 自定义列表 *

* * @author hai ji @@ -17,31 +17,45 @@ public interface List { //查询列表当前的规模 int size(); + //判断列表是否为空 boolean isEmpty(); + //返回第一个元素(的位置) Position first(); + //返回最后一个元素(的位置) Position last(); + //返回紧接给定位置之后的元素(的位置) Position getNext(Position p) throws ExceptionPositionInvalid, ExceptionBoundaryViolation; + //返回紧靠给定位置之前的元素(的位置) Position getPrev(Position p) throws ExceptionPositionInvalid, ExceptionBoundaryViolation; + //将e作为第一个元素插入列表 Position insertFirst(E e); + //将e作为最后一个元素插入列表 Position insertLast(E e); + //将e插入至紧接给定位置之后的位置 Position insertAfter(Position p, E e) throws ExceptionPositionInvalid; + //将e插入至紧靠给定位置之前的位置 Position insertBefore(Position p, E e) throws ExceptionPositionInvalid; + //删除给定位置处的元素,并返回之 E remove(Position p) throws ExceptionPositionInvalid; + //删除首元素,并返回之 E removeFirst(); + //删除末元素,并返回之 E removeLast(); + //将处于给定位置的元素替换为新元素,并返回被替换的元素 - E replace(Position p, E e) throws ExceptionPositionInvalid; + E replace(Position p, E e) throws ExceptionPositionInvalid; + Iterator elements(); } diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/list/NodeList.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/list/NodeList.java index df514b4..8498539 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/list/NodeList.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/list/NodeList.java @@ -17,7 +17,7 @@ * @version 1.0.0 * @since 2020-08-26 */ -public class NodeList implements List{ +public class NodeList implements List { //列表的实际规模 protected int numElem; //哨兵:首节点+末节点 @@ -60,7 +60,7 @@ public Position last() { public Position getNext(Position p) throws ExceptionPositionInvalid, ExceptionBoundaryViolation { Node v = checkPosition(p); Node next = v.getNext(); - if (next == trailer){ + if (next == trailer) { throw new ExceptionBoundaryViolation("意外:企图越过列表后端"); } return next; @@ -152,6 +152,7 @@ public E replace(Position p, E element) throws ExceptionPositionInvalid { /** * 检查给定位置在列表中是否合法,若是,则将其转换为 Node + * * @param p * @return * @throws ExceptionPositionInvalid @@ -166,18 +167,18 @@ protected Node checkPosition(Position p) throws ExceptionPositionInvalid { if (trailer == p) { throw new ExceptionPositionInvalid("意外:尾结点哨兵位置非法"); } - Node temp = (Node)p; + Node temp = (Node) p; return temp; } - protected void isNull(){ - if (isEmpty()){ + protected void isNull() { + if (isEmpty()) { throw new ExceptionListEmpty("意外:列表空"); } } @Override - public Iterator elements(){ + public Iterator elements() { return new IteratorElement(this); } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/LinkedQueue.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/LinkedQueue.java index f62ec13..b862ec4 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/LinkedQueue.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/LinkedQueue.java @@ -13,7 +13,7 @@ * @version 1.0.0 * @since 2020-08-21 */ -public class LinkedQueue implements Queue{ +public class LinkedQueue implements Queue { //指向表首元素 protected Node head; //指向表末元素 @@ -48,10 +48,10 @@ public void enqueue(E e) throws ExceptionQueueFull { Node node = new Node<>(); node.setElem(e); node.setNext(null); - if (0 == size){ + if (0 == size) { //若此前队列为空,则直接插入 head = node; - }else { + } else { tail.setNext(node); } //更新指向末节点引用 @@ -62,14 +62,14 @@ public void enqueue(E e) throws ExceptionQueueFull { @Override public E dequeue() throws ExceptionQueueEmpty { - if(isEmpty()){ + if (isEmpty()) { throw new ExceptionQueueEmpty("意外:队列空"); } E old = head.getElem(); head = head.getNext(); size--; //若队列已空,须将末节点引用置空 - if (0 == size){ + if (0 == size) { tail = null; } return old; diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/Queue.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/Queue.java index 9c558ef..620e361 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/Queue.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/Queue.java @@ -16,18 +16,21 @@ public interface Queue { /** * 返回队列的长度 + * * @return */ int size(); /** * 判断队列是否为空 + * * @return */ boolean isEmpty(); /** * 获取队列第一个元素,但是不删除 + * * @return * @throws ExceptionQueueEmpty */ @@ -35,13 +38,15 @@ public interface Queue { /** * 入队 + * * @param e * @throws ExceptionQueueFull */ - void enqueue (E e) throws ExceptionQueueFull; + void enqueue(E e) throws ExceptionQueueFull; /** * 出队 + * * @return * @throws ExceptionQueueEmpty */ diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/QueueArray.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/QueueArray.java index aef0cf7..7bbae3d 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/QueueArray.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/QueueArray.java @@ -12,7 +12,7 @@ * @version 1.0.0 * @since 2020-08-20 */ -public class QueueArray implements Queue{ +public class QueueArray implements Queue { transient Object[] elementData; //默认长度 @@ -32,8 +32,8 @@ public QueueArray() { } public QueueArray(int initialCapacity) { - if(initialCapacity < 0){ - throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); + if (initialCapacity < 0) { + throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); } capacity = initialCapacity; this.elementData = new Object[initialCapacity]; @@ -43,7 +43,7 @@ public QueueArray(int initialCapacity) { @Override public int size() { - return (capacity - fist +last) % capacity; + return (capacity - fist + last) % capacity; } @Override @@ -59,7 +59,7 @@ public E front() throws ExceptionQueueEmpty { @Override public void enqueue(E e) throws ExceptionQueueFull { - if(size() == capacity-1){ + if (size() == capacity - 1) { throw new ExceptionQueueFull("Queue overflow."); } elementData[last] = e; @@ -68,15 +68,15 @@ public void enqueue(E e) throws ExceptionQueueFull { @Override public E dequeue() throws ExceptionQueueEmpty { - E element ; + E element; assertEmpty(); element = elementData(fist); - elementData[fist] =null; - fist = (fist + 1) %capacity; + elementData[fist] = null; + fist = (fist + 1) % capacity; return element; } - protected void assertEmpty(){ + protected void assertEmpty() { if (isEmpty()) { throw new ExceptionQueueEmpty("意外:队列空"); } diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/QueueTest.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/QueueTest.java index 179c7dd..972d428 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/QueueTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/queue/QueueTest.java @@ -5,7 +5,7 @@ /** *

- * 测试队列 + * 测试队列 *

* * @author hai ji diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/skiplist/SkipList.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/skiplist/SkipList.java index 64a1d58..645f9ae 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/skiplist/SkipList.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/skiplist/SkipList.java @@ -11,150 +11,159 @@ * @version 1.0.0 * @since 2020-10-13 */ -public class SkipList { - private SkipListNode head,tail; +public class SkipList { + private SkipListNode head, tail; private int nodes;//节点总数 private int listLevel;//层数 private Random random;// 用于投掷硬币 - private static final double PROBABILITY=0.5;//向上提升一个的概率 + private static final double PROBABILITY = 0.5;//向上提升一个的概率 + public SkipList() { // TODO Auto-generated constructor stub - random=new Random(); + random = new Random(); clear(); } + /** - *清空跳跃表 - * */ - public void clear(){ - head=new SkipListNode(SkipListNode.HEAD_KEY, null); - tail=new SkipListNode(SkipListNode.TAIL_KEY, null); + * 清空跳跃表 + */ + public void clear() { + head = new SkipListNode(SkipListNode.HEAD_KEY, null); + tail = new SkipListNode(SkipListNode.TAIL_KEY, null); horizontalLink(head, tail); - listLevel=0; - nodes=0; + listLevel = 0; + nodes = 0; } - public boolean isEmpty(){ - return nodes==0; + + public boolean isEmpty() { + return nodes == 0; } public int size() { return nodes; } + /** * 在最下面一层,找到要插入的位置前面的那个key - * */ - private SkipListNode findNode(int key){ - SkipListNode p=head; - while(true){ - while (p.right.key!=SkipListNode.TAIL_KEY&&p.right.key<=key) { - p=p.right; + */ + private SkipListNode findNode(int key) { + SkipListNode p = head; + while (true) { + while (p.right.key != SkipListNode.TAIL_KEY && p.right.key <= key) { + p = p.right; } - if (p.down!=null) { - p=p.down; - }else { + if (p.down != null) { + p = p.down; + } else { break; } } return p; } + /** * 查找是否存储key,存在则返回该节点,否则返回null - * */ - public SkipListNode search(int key){ - SkipListNode p=findNode(key); - if (key==p.getKey()) { + */ + public SkipListNode search(int key) { + SkipListNode p = findNode(key); + if (key == p.getKey()) { return p; - }else { + } else { return null; } } + /** * 向跳跃表中添加key-value - * - * */ - public void put(int k,T v){ - SkipListNode p=findNode(k); + */ + public void put(int k, T v) { + SkipListNode p = findNode(k); //如果key值相同,替换原来的vaule即可结束 - if (k==p.getKey()) { - p.value=v; + if (k == p.getKey()) { + p.value = v; return; } - SkipListNode q=new SkipListNode(k, v); + SkipListNode q = new SkipListNode(k, v); backLink(p, q); - int currentLevel=0;//当前所在的层级是0 + int currentLevel = 0;//当前所在的层级是0 //抛硬币 - while (random.nextDouble()=listLevel) { + if (currentLevel >= listLevel) { listLevel++; - SkipListNode p1=new SkipListNode(SkipListNode.HEAD_KEY, null); - SkipListNode p2=new SkipListNode(SkipListNode.TAIL_KEY, null); + SkipListNode p1 = new SkipListNode(SkipListNode.HEAD_KEY, null); + SkipListNode p2 = new SkipListNode(SkipListNode.TAIL_KEY, null); horizontalLink(p1, p2); vertiacallLink(p1, head); vertiacallLink(p2, tail); - head=p1; - tail=p2; + head = p1; + tail = p2; } //将p移动到上一层 - while (p.up==null) { - p=p.left; + while (p.up == null) { + p = p.left; } - p=p.up; + p = p.up; - SkipListNode e=new SkipListNode(k, null);//只保存key就ok + SkipListNode e = new SkipListNode(k, null);//只保存key就ok backLink(p, e);//将e插入到p的后面 vertiacallLink(e, q);//将e和q上下连接 - q=e; + q = e; currentLevel++; } nodes++;//层数递增 } + //node1后面插入node2 - private void backLink(SkipListNode node1,SkipListNode node2){ - node2.left=node1; - node2.right=node1.right; - node1.right.left=node2; - node1.right=node2; + private void backLink(SkipListNode node1, SkipListNode node2) { + node2.left = node1; + node2.right = node1.right; + node1.right.left = node2; + node1.right = node2; } + /** * 水平双向连接 - * */ - private void horizontalLink(SkipListNode node1,SkipListNode node2){ - node1.right=node2; - node2.left=node1; + */ + private void horizontalLink(SkipListNode node1, SkipListNode node2) { + node1.right = node2; + node2.left = node1; } + /** * 垂直双向连接 - * */ - private void vertiacallLink(SkipListNode node1,SkipListNode node2){ - node1.down=node2; - node2.up=node1; + */ + private void vertiacallLink(SkipListNode node1, SkipListNode node2) { + node1.down = node2; + node2.up = node1; } + /** * 打印出原始数据 - * */ + */ @Override public String toString() { // TODO Auto-generated method stub if (isEmpty()) { return "跳跃表为空!"; } - StringBuilder builder=new StringBuilder(); - SkipListNode p=head; - while (p.down!=null) { - p=p.down; + StringBuilder builder = new StringBuilder(); + SkipListNode p = head; + while (p.down != null) { + p = p.down; } - while (p.left!=null) { - p=p.left; + while (p.left != null) { + p = p.left; } - if (p.right!=null) { - p=p.right; + if (p.right != null) { + p = p.right; } - while (p.right!=null) { + while (p.right != null) { builder.append(p); builder.append("\n"); - p=p.right; + p = p.right; } return builder.toString(); diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/skiplist/SkipListNode.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/skiplist/SkipListNode.java index 0468410..7c85712 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/skiplist/SkipListNode.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/skiplist/SkipListNode.java @@ -9,35 +9,41 @@ * @version 1.0.0 * @since 2020-10-13 */ -public class SkipListNode { +public class SkipListNode { public int key; public T value; public SkipListNode up, down, left, right; // 上下左右 四个指针 public static final int HEAD_KEY = Integer.MIN_VALUE; // 负无穷 - public static final int TAIL_KEY = Integer.MAX_VALUE; // 正无穷 - public SkipListNode(int k,T v) { + public static final int TAIL_KEY = Integer.MAX_VALUE; // 正无穷 + + public SkipListNode(int k, T v) { // TODO Auto-generated constructor stub key = k; value = v; } + public int getKey() { return key; } + public void setKey(int key) { this.key = key; } + public T getValue() { return value; } + public void setValue(T value) { this.value = value; } + public boolean equals(Object o) { - if (this==o) { + if (this == o) { return true; } - if (o==null) { + if (o == null) { return false; } if (!(o instanceof SkipListNode)) { @@ -45,15 +51,16 @@ public boolean equals(Object o) { } SkipListNode ent; try { - ent = (SkipListNode) o; // 检测类型 + ent = (SkipListNode) o; // 检测类型 } catch (ClassCastException ex) { return false; } return (ent.getKey() == key) && (ent.getValue() == value); } + @Override public String toString() { // TODO Auto-generated method stub - return "key-value:"+key+"-"+value; + return "key-value:" + key + "-" + value; } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/LinkedStack.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/LinkedStack.java index 655754a..ee6957c 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/LinkedStack.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/LinkedStack.java @@ -12,7 +12,7 @@ * @version 1.0.0 * @since 2020-08-21 */ -public class LinkedStack implements Stack{ +public class LinkedStack implements Stack { //指向栈顶元素 private Node top; @@ -20,8 +20,8 @@ public class LinkedStack implements Stack{ private int size; public LinkedStack() { - this.size=0; - this.top=null; + this.size = 0; + this.top = null; } @Override @@ -30,14 +30,14 @@ public void push(E e) { //Node node = new Node<>(e,top); //更新首节点引用 //top = node; - top = new Node<>(e,top); + top = new Node<>(e, top); //更新操作长度 - size ++; + size++; } @Override public E pop() throws ExceptionStackEmpty { - if (isEmpty()){ + if (isEmpty()) { throw new ExceptionStackEmpty("意外:栈空"); } //获取当前的节点 @@ -61,7 +61,7 @@ public boolean isEmpty() { @Override public E top() throws ExceptionStackEmpty { - if (isEmpty()){ + if (isEmpty()) { throw new ExceptionStackEmpty("意外:栈空"); } return (E) top.getElem(); diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/Stack.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/Stack.java index a881603..53d4e64 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/Stack.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/Stack.java @@ -4,7 +4,7 @@ /** *

- * 自定义栈 + * 自定义栈 *

* * @author hai ji @@ -15,6 +15,7 @@ public interface Stack { /** * 入栈 + * * @param e */ void push(E e); @@ -26,18 +27,21 @@ public interface Stack { /** * 获取长度 + * * @return */ int size(); /** * 判断是否为空 + * * @return */ boolean isEmpty(); /** * 取栈顶元素(但不删除) + * * @return * @throws ExceptionStackEmpty */ diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/StackArray.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/StackArray.java index e7feb49..255dcef 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/StackArray.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/StackArray.java @@ -30,26 +30,25 @@ public StackArray() { } public StackArray(int initialCapacity) { - if(initialCapacity > 0){ + if (initialCapacity > 0) { capacity = initialCapacity; this.elementData = new Object[initialCapacity]; - } - else if(initialCapacity == 0){ + } else if (initialCapacity == 0) { capacity = DEFAULT_CAPACITY; this.elementData = new Object[DEFAULT_CAPACITY]; - } - else{ - throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); + } else { + throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); } } /** * 入栈 + * * @param e */ @Override public void push(E e) { - if (size() == capacity){ + if (size() == capacity) { throw new ExceptionStackFull("意外:栈溢出"); } elementData[++top] = e; @@ -57,6 +56,7 @@ public void push(E e) { /** * 出栈 + * * @return * @throws ExceptionStackEmpty */ @@ -71,6 +71,7 @@ public E pop() throws ExceptionStackEmpty { /** * 获取长度 + * * @return */ @Override @@ -80,6 +81,7 @@ public int size() { /** * 是否为空 + * * @return */ @Override @@ -89,6 +91,7 @@ public boolean isEmpty() { /** * 获取最顶端元素 + * * @return * @throws ExceptionStackEmpty */ @@ -98,7 +101,7 @@ public E top() throws ExceptionStackEmpty { return elementData(top); } - protected void assertEmpty(){ + protected void assertEmpty() { if (isEmpty()) { throw new ExceptionStackEmpty("意外:栈空"); } diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/StackTest.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/StackTest.java index 3f23ca2..85d0bc7 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/StackTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/stack/StackTest.java @@ -2,7 +2,7 @@ /** *

- * 测试 + * 测试 *

* * @author hai ji @@ -11,12 +11,12 @@ */ public class StackTest { public static void main(String[] args) { - Stack stack = new StackArray<>(); + Stack stack = new StackArray<>(); stack.push("haiji"); stack.push("yang"); String pop = stack.pop(); System.out.println(pop); - Stack stackList = new LinkedStack<>(); + Stack stackList = new LinkedStack<>(); stackList.push("haiji"); stackList.push("yang"); String popList = stackList.pop(); diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTree.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTree.java index 5ec89e5..f77d2f1 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTree.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTree.java @@ -4,7 +4,7 @@ /** *

- * 二叉树 + * 二叉树 *

* * @author hai ji @@ -15,8 +15,9 @@ public interface BinTree { /** *

- * 获取根节点 + * 获取根节点 *

+ * * @param * @return com.javayh.advanced.java.datastructure.tree.bin.BinTreePosition */ @@ -24,8 +25,9 @@ public interface BinTree { /** *

- * 判断是否为空 + * 判断是否为空 *

+ * * @param * @return boolean */ @@ -33,14 +35,16 @@ public interface BinTree { /** * 返回树的规模,即树根的后代数目 + * * @return int */ int size(); /** *

- * 返回树的高度 + * 返回树的高度 *

+ * * @param * @return int */ @@ -48,8 +52,9 @@ public interface BinTree { /** *

- * 前序遍历 + * 前序遍历 *

+ * * @param * @return com.javayh.advanced.java.datastructure.Iterator */ @@ -57,8 +62,9 @@ public interface BinTree { /** *

- * 中序遍历 + * 中序遍历 *

+ * * @param * @return com.javayh.advanced.java.datastructure.Iterator */ @@ -66,17 +72,19 @@ public interface BinTree { /** *

- * 后序遍历 + * 后序遍历 *

- * @param + * + * @param * @return com.javayh.advanced.java.datastructure.Iterator */ Iterator elementsPostorder(); /** *

- * 层次遍历 + * 层次遍历 *

+ * * @param * @return com.javayh.advanced.java.datastructure.Iterator */ diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreeLinkedList.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreeLinkedList.java index 6454eb4..743eaa8 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreeLinkedList.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreeLinkedList.java @@ -14,61 +14,59 @@ public class BinTreeLinkedList implements BinTree { protected BinTreePosition root;//根节点 - public BinTreeLinkedList() - { + public BinTreeLinkedList() { this(null); } - public BinTreeLinkedList(BinTreePosition r) - { + + public BinTreeLinkedList(BinTreePosition r) { root = r; } + //返回树根 @Override - public BinTreePosition getRoot() - { + public BinTreePosition getRoot() { return root; } + //判断是否树空 @Override - public boolean isEmpty() - { + public boolean isEmpty() { return null == root; } //返回树的规模(即树根的后代数目) @Override - public int size() - { + public int size() { return isEmpty() ? 0 : root.getSize(); } + //返回树(根)的高度 @Override - public int getHeight() - { + public int getHeight() { return isEmpty() ? -1 : root.getHeight(); } + //前序遍历 @Override - public Iterator elementsPreorder() - { + public Iterator elementsPreorder() { return root.elementsPreorder(); } + //中序遍历 @Override - public Iterator elementsInorder() - { + public Iterator elementsInorder() { return root.elementsInorder(); } + //后序遍历 @Override - public Iterator elementsPostorder() - { + public Iterator elementsPostorder() { return root.elementsPostorder(); } + //层次遍历 @Override - public Iterator elementsLevelorder() - { + public Iterator elementsLevelorder() { return root.elementsLevelorder(); } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreeNode.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreeNode.java index df00678..9ca69f2 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreeNode.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreeNode.java @@ -17,7 +17,7 @@ * @version 1.0.0 * @since 2020-09-08 */ -public class BinTreeNode implements BinTreePosition{ +public class BinTreeNode implements BinTreePosition { protected E element;//该节点中存放的对象 protected BinTreePosition parent;//父亲 @@ -26,8 +26,8 @@ public class BinTreeNode implements BinTreePosition{ protected int size;//后代数目 protected int height;//高度 protected int depth;//深度 - public BinTreeNode() - { + + public BinTreeNode() { this(null, null, true, null, null); } @@ -38,14 +38,18 @@ public BinTreeNode( BinTreePosition l,//左孩子 BinTreePosition r)//右孩子 { - size = 1; height = depth = 0; parent = lChild = rChild = null;//初始化 + size = 1; + height = depth = 0; + parent = lChild = rChild = null;//初始化 element = e;//存放的对象 //建立与父亲的关系 - if (null != p){ - if (asLChild){ + if (null != p) { + if (asLChild) { p.attachL(this); } - }else {p.attachR(this);} + } else { + p.attachR(this); + } //建立与孩子的关系 if (null != l) { attachL(l); @@ -54,6 +58,7 @@ public BinTreeNode( attachR(r); } } + @Override public boolean hasParent() { return null != parent; @@ -66,7 +71,7 @@ public BinTreePosition getParent() { @Override public void setParent(BinTreePosition p) { - this.parent=p; + this.parent = p; } @Override @@ -76,8 +81,9 @@ public boolean isLeaf() { /** *

- * 若当前节点有父亲,而且是左孩子,则返回true;否则,返回false + * 若当前节点有父亲,而且是左孩子,则返回true;否则,返回false *

+ * * @param * @return boolean */ @@ -88,7 +94,7 @@ public boolean isLChild() { @Override public boolean hasLChild() { - return null != lChild; + return null != lChild; } @Override @@ -103,9 +109,10 @@ public void setLChild(BinTreePosition c) { /** *

- * 判断是否为右孩子(为使代码描述简洁) - * 若当前节点有父亲,而且是右孩子,则返回true;否则,返回false + * 判断是否为右孩子(为使代码描述简洁) + * 若当前节点有父亲,而且是右孩子,则返回true;否则,返回false *

+ * * @param * @return boolean */ @@ -138,13 +145,13 @@ public int getSize() { public void updateSize() { //当前节点 size = 1; - if(hasLChild()){ + if (hasLChild()) { size += getLChild().getSize(); } - if (hasRChild()){ + if (hasRChild()) { size += getRChild().getSize(); } - if (hasParent()){//递归更新各个真祖先的规模记录 + if (hasParent()) {//递归更新各个真祖先的规模记录 getParent().updateSize(); } } @@ -161,11 +168,11 @@ public int getHeight() { public void updateHeight() { //先假设没有左、右孩子 height = 0; - if(hasLChild()){ - this.height = Math.max(height,1+getLChild().getHeight()); + if (hasLChild()) { + this.height = Math.max(height, 1 + getLChild().getHeight()); }// - if(hasRChild()){ - height = Math.max(height, 1+getRChild().getHeight()); + if (hasRChild()) { + height = Math.max(height, 1 + getRChild().getHeight()); } if (hasParent()) {//递归更新各个真祖先的高度记录 getParent().updateHeight(); @@ -182,7 +189,7 @@ public int getDepth() { */ @Override public void updateDepth() { - depth = hasParent() ? 1+getParent().getDepth() : 0;//当前节点 + depth = hasParent() ? 1 + getParent().getDepth() : 0;//当前节点 if (hasLChild()) { getLChild().updateDepth();//沿孩子引用逐层向下, } @@ -193,6 +200,7 @@ public void updateDepth() { /** * /按照中序遍历的次序,找到当前节点的直接前驱 + * * @return */ @Override @@ -207,7 +215,7 @@ public BinTreePosition getPrev() { } //至此,当前节点没有左孩子,而且是左孩子 BinTreePosition v = this;//从当前节点出发 - while (v.isLChild()){ + while (v.isLChild()) { v = v.getParent();//沿左孩子链一直上升 } //至此,v或者没有父亲,或者是父亲的右孩子 @@ -216,6 +224,7 @@ public BinTreePosition getPrev() { /** * 按照中序遍历的次序,找到当前节点的直接后继 + * * @return */ @Override @@ -242,8 +251,7 @@ public BinTreePosition secede() { if (null != parent) { if (isLChild()) { parent.setLChild(null);//切断父亲指向当前节点的引用 - } - else { + } else { parent.setRChild(null); } parent.updateSize();//更新当前节点及其祖先的规模 @@ -256,6 +264,7 @@ public BinTreePosition secede() { /** * 将节点c作为当前节点的左孩子 + * * @param c * @return */ @@ -266,7 +275,8 @@ public BinTreePosition attachL(BinTreePosition c) { } if (null != c) { c.secede();//c脱离原父亲 - lChild = c; c.setParent(this);//确立新的父子关系 + lChild = c; + c.setParent(this);//确立新的父子关系 updateSize();//更新当前节点及其祖先的规模 updateHeight();//更新当前节点及其祖先的高度 c.updateDepth();//更新c及其后代节点的深度 @@ -276,6 +286,7 @@ public BinTreePosition attachL(BinTreePosition c) { /** * 将节点c作为当前节点的右孩子 + * * @param c * @return */ @@ -286,7 +297,8 @@ public BinTreePosition attachR(BinTreePosition c) { } if (null != c) { c.secede();//c脱离原父亲 - rChild = c; c.setParent(this);//确立新的父子关系 + rChild = c; + c.setParent(this);//确立新的父子关系 updateSize();//更新当前节点及其祖先的规模 updateHeight();//更新当前节点及其祖先的高度 c.updateDepth();//更新c及其后代节点的深度 @@ -341,6 +353,7 @@ protected static BinTreePosition findMinDescendant(BinTreePosition v) { //至此,v或者为空,或者没有左孩子 return v; } + //在v的后代中,找出最大者 protected static BinTreePosition findMaxDescendant(BinTreePosition v) { if (null != v) @@ -348,6 +361,7 @@ protected static BinTreePosition findMaxDescendant(BinTreePosition v) { //至此,v或者为空,或者没有右孩子 return v; } + //前序遍历以v为根节的(子)树 protected static void preorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 @@ -355,6 +369,7 @@ protected static void preorder(List list, BinTreePosition v) { preorder(list, v.getLChild());//遍历左子树 preorder(list, v.getRChild());//遍历右子树 } + //中序遍历以v为根节的(子)树 protected static void inorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 @@ -362,6 +377,7 @@ protected static void inorder(List list, BinTreePosition v) { list.insertLast(v);//访问v inorder(list, v.getRChild());//遍历右子树 } + //后序遍历以v为根节的(子)树 protected static void postorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 @@ -369,6 +385,7 @@ protected static void postorder(List list, BinTreePosition v) { postorder(list, v.getRChild());//遍历右子树 list.insertLast(v);//访问v } + //层次遍历以v为根节的(子)树 @SneakyThrows protected static void levelorder(List list, BinTreePosition v) { diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreePosition.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreePosition.java index 76c650c..76c6a88 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreePosition.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/bin/BinTreePosition.java @@ -16,57 +16,83 @@ public interface BinTreePosition extends Position { //判断是否有父亲 boolean hasParent(); + //返回当前节点的父节点 BinTreePosition getParent(); + //设置当前节点的父节点 void setParent(BinTreePosition p); + //判断是否为叶子 boolean isLeaf(); + //判断是否为左孩子(为使代码描述简洁) boolean isLChild(); + //判断是否有左孩子(为使代码描述简洁) boolean hasLChild(); + //返回当前节点的左孩子 BinTreePosition getLChild(); + //设置当前节点的左孩子(注意:this.lChild和c.parent都不一定为空) void setLChild(BinTreePosition c); + //判断是否为右孩子(为使代码描述简洁) boolean isRChild(); + //判断是否有右孩子(为使代码描述简洁) boolean hasRChild(); + //返回当前节点的右孩子 BinTreePosition getRChild(); + //设置当前节点的右孩子(注意:this.rChild和c.parent都不一定为空) void setRChild(BinTreePosition c); + //返回当前节点后代元素的数目 int getSize(); + //在孩子发生变化后,更新当前节点及其祖先的规模 void updateSize(); + //返回当前节点的高度 int getHeight(); + //在孩子发生变化后,更新当前节点及其祖先的高度 void updateHeight(); + //返回当前节点的深度 int getDepth(); + //在父亲发生变化后,更新当前节点及其后代的深度 void updateDepth(); + //按照中序遍历的次序,找到当前节点的直接前驱 BinTreePosition getPrev(); + //按照中序遍历的次序,找到当前节点的直接后继 BinTreePosition getSucc(); + //断绝当前节点与其父亲的父子关系 //返回当前节点 BinTreePosition secede(); + //将节点c作为当前节点的左孩子 BinTreePosition attachL(BinTreePosition c); + //将节点c作为当前节点的右孩子 BinTreePosition attachR(BinTreePosition c); + //前序遍历 Iterator elementsPreorder(); + //中序遍历 Iterator elementsInorder(); + //后序遍历 Iterator elementsPostorder(); + //层次遍历 Iterator elementsLevelorder(); } diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/IteratorTree.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/IteratorTree.java index 09a8a3d..e32a441 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/IteratorTree.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/IteratorTree.java @@ -20,11 +20,17 @@ public class IteratorTree implements Iterator { private List list;//列表 private Position nextPosition;//当前(下一个)元素的位置 + //默认构造方法 - public IteratorTree() { list = null; } + public IteratorTree() { + list = null; + } + //前序遍历 public void elementsPreorderIterator(TreeLinkedList T) { - if (null == T) {return;}//递归基 + if (null == T) { + return; + }//递归基 list.insertLast(T);//首先输出当前节点 TreeLinkedList subtree = T.getFirstChild();//从当前节点的长子开始 while (null != subtree) {//依次对当前节点的各个孩子 @@ -32,6 +38,7 @@ public void elementsPreorderIterator(TreeLinkedList T) { subtree = subtree.getNextSibling(); } } + //后序遍历 public void elementsPostorderIterator(TreeLinkedList T) { if (null == T) return;//递归基 @@ -42,6 +49,7 @@ public void elementsPostorderIterator(TreeLinkedList T) { } list.insertLast(T);//当所有后代都访问过后,最后才访问当前节点 } + //层次遍历 @SneakyThrows public void levelTraversalIterator(TreeLinkedList T) { @@ -75,8 +83,7 @@ public E next() { Position currentPosition = nextPosition; if (currentPosition == list.last()) {//若已到达尾元素,则 nextPosition = null;//不再有下一元素 - } - else {//否则 + } else {//否则 nextPosition = list.getNext(currentPosition);//转向下一元素 } return (E) currentPosition.getElem(); diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/Tree.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/Tree.java index d721ccd..a6d43d6 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/Tree.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/Tree.java @@ -11,16 +11,17 @@ * @version 1.0.0 * @since 2020-09-07 */ -public interface Tree -{ +public interface Tree { /** * 返回当前节点存放的对象 + * * @return */ E getElem(); /** * 将element 存放到当前节点,并返回此前对象 + * * @param element * @return */ @@ -28,36 +29,42 @@ public interface Tree /** * 返回当前节点的父节点 + * * @return */ TreeLinkedList getParent(); /** * 返回当前节点的长子 + * * @return */ TreeLinkedList getFirstChild(); /** * 返回当前节点的最大弟弟 + * * @return */ TreeLinkedList getNextSibling(); /** * 返回当前节点后代元素的数目,即以当前节点为根的子树的规模 + * * @return */ int size(); /** * 返回当前节点的高度 + * * @return */ int getHeight(); /** * 返回当前节点的深度 + * * @return */ int getDepth(); diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/TreeLinkedList.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/TreeLinkedList.java index 35f2546..194c3a7 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/TreeLinkedList.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/tree/linked/TreeLinkedList.java @@ -11,14 +11,18 @@ */ public class TreeLinkedList implements Tree { - /**根节点*/ + /** + * 根节点 + */ private E element; - /**父亲、长子及最大的弟弟*/ + /** + * 父亲、长子及最大的弟弟 + */ private TreeLinkedList parent, firstChild, nextSibling; public TreeLinkedList() { - this(null,null,null,null); + this(null, null, null, null); } public TreeLinkedList(E element, TreeLinkedList parent, TreeLinkedList firstChild, TreeLinkedList nextSibling) { @@ -52,8 +56,9 @@ public TreeLinkedList getFirstChild() { /** *

- * 返回当前节点的最大弟弟;若没有弟弟,则返回null + * 返回当前节点的最大弟弟;若没有弟弟,则返回null *

+ * * @return com.javayh.advanced.java.datastructure.tree.linked.TreeLinkedList */ @Override @@ -75,8 +80,7 @@ public int size() { int size = 1; //从长子开始 TreeLinkedList subtree = firstChild; - while (null != subtree) - { // 累加 + while (null != subtree) { // 累加 size += subtree.size(); // 所有孩子的后代数目 subtree = subtree.getNextSibling(); @@ -94,12 +98,12 @@ public int getHeight() { int height = -1; //从长子开始 TreeLinkedList subtree = firstChild; - while (null != subtree){ + while (null != subtree) { //在所有孩子中取最大的高度 - height = Math.max(height,subtree.getHeight()); + height = Math.max(height, subtree.getHeight()); subtree = subtree.getNextSibling(); } - return height+1; + return height + 1; } @Override diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/ArrayVector.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/ArrayVector.java index db020cf..0c82399 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/ArrayVector.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/ArrayVector.java @@ -4,14 +4,14 @@ /** *

- * 基于数组实现的向量 + * 基于数组实现的向量 *

* * @author hai ji * @version 1.0.0 * @since 2020-08-22 */ -public class ArrayVector implements Vector{ +public class ArrayVector implements Vector { //数组的容量 private final int DEFAULT_CAPACITY = 1024; //向量的实际规模 @@ -21,7 +21,7 @@ public class ArrayVector implements Vector{ public ArrayVector() { this.elementData = new Object[DEFAULT_CAPACITY]; - this.size=0; + this.size = 0; } @Override @@ -57,7 +57,7 @@ public E insertAtRank(int r, E obj) throws ExceptionBoundaryViolation { if (0 > r || r >= DEFAULT_CAPACITY) { throw new ExceptionBoundaryViolation("意外:秩越界"); } - if (size >= DEFAULT_CAPACITY){ + if (size >= DEFAULT_CAPACITY) { throw new ExceptionBoundaryViolation("意外:数组溢出"); } /*for (int i= size; i > r; i--) { diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/ExtArrayVector.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/ExtArrayVector.java index 8965637..2432b30 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/ExtArrayVector.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/ExtArrayVector.java @@ -4,14 +4,14 @@ /** *

- * 动态扩容 + * 动态扩容 *

* * @author hai ji * @version 1.0.0 * @since 2020-08-22 */ -public class ExtArrayVector implements Vector{ +public class ExtArrayVector implements Vector { private int DEFAULT_CAPACITY = 16; //向量的实际规模 @@ -25,7 +25,7 @@ public ExtArrayVector() { } public ExtArrayVector(int initialCapacity) { - if(initialCapacity < 0){ + if (initialCapacity < 0) { throw new ExceptionBoundaryViolation("initialCapacity :" + initialCapacity); } this.elementData = new Object[initialCapacity]; @@ -44,7 +44,7 @@ public boolean isEmpty() { @Override public E getAtRank(int r) throws ExceptionBoundaryViolation { - if(0 > r || r >size){ + if (0 > r || r > size) { throw new ExceptionBoundaryViolation("下标越界"); } return elementData(r); @@ -52,7 +52,7 @@ public E getAtRank(int r) throws ExceptionBoundaryViolation { @Override public E replaceAtRank(int r, E obj) throws ExceptionBoundaryViolation { - if(r > size){ + if (r > size) { throw new ExceptionBoundaryViolation("下标越界"); } E oldEle = elementData(r); @@ -62,7 +62,7 @@ public E replaceAtRank(int r, E obj) throws ExceptionBoundaryViolation { @Override public E insertAtRank(int r, E obj) throws ExceptionBoundaryViolation { - if(0 > r){ + if (0 > r) { throw new ExceptionBoundaryViolation("下标越界"); } //空间溢出的处理 @@ -70,7 +70,7 @@ public E insertAtRank(int r, E obj) throws ExceptionBoundaryViolation { DEFAULT_CAPACITY *= 2; //开辟一个容量加倍的数组 Object[] elementCopy = new Object[DEFAULT_CAPACITY]; - for (int i=0; ir; i--) { - elementData[i] = elementData[i-1]; + for (int i = size; i > r; i--) { + elementData[i] = elementData[i - 1]; } elementData[r] = obj;//插入 size++;//更新当前规模 @@ -88,7 +88,7 @@ public E insertAtRank(int r, E obj) throws ExceptionBoundaryViolation { @Override public E removeAtRank(int r) throws ExceptionBoundaryViolation { - if(0 > r || r > size){ + if (0 > r || r > size) { throw new ExceptionBoundaryViolation("下标越界"); } E oldEle = elementData(r); diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/Vector.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/Vector.java index fa34a87..0b58033 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/Vector.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/Vector.java @@ -15,18 +15,21 @@ public interface Vector { /** * 返回向量中元素数目 + * * @return */ int size(); /** * 判断向量是否为空 + * * @return */ boolean isEmpty(); /** * 取秩为r的元素 + * * @param r * @return * @throws ExceptionBoundaryViolation @@ -35,6 +38,7 @@ public interface Vector { /** * 替换指定下标的元素 + * * @param r * @param obj * @return @@ -44,6 +48,7 @@ public interface Vector { /** * 插入obj,作为秩为r的元素;返回该元素 + * * @param r * @param obj * @return @@ -52,6 +57,7 @@ public interface Vector { /** * 删除秩为r的元素 + * * @param r * @return * @throws ExceptionBoundaryViolation diff --git a/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/VectorTest.java b/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/VectorTest.java index 5b97ba6..0603e24 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/VectorTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/datastructure/vector/VectorTest.java @@ -12,10 +12,10 @@ public class VectorTest { public static void main(String[] args) { Vector vector = new ArrayVector<>(); - vector.insertAtRank(0,"Java"); - vector.insertAtRank(1,"Java"); - vector.insertAtRank(2,"Java"); - vector.insertAtRank(3,"Java"); + vector.insertAtRank(0, "Java"); + vector.insertAtRank(1, "Java"); + vector.insertAtRank(2, "Java"); + vector.insertAtRank(3, "Java"); System.out.println(vector.getAtRank(2)); System.out.println(vector.removeAtRank(2)); System.out.println(vector.replaceAtRank(1, "Haiji")); diff --git a/source-code/src/main/java/com/javayh/advanced/java/jvm/JvmParamTest.java b/source-code/src/main/java/com/javayh/advanced/java/jvm/JvmParamTest.java index fbf709d..6baefbb 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/jvm/JvmParamTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/jvm/JvmParamTest.java @@ -5,7 +5,7 @@ /** *

- * jvm 参数 + * jvm 参数 *

* * @author Dylan @@ -15,34 +15,34 @@ public class JvmParamTest { /** - * 1.设置最大/小 heap - * -Xmx10m/-Xms10m - * 2.添加gc log - * -XX:+PrintGCDetails - * 3.添加gc记录文件 - * -Xloggc:文件名 - * 4.选择垃圾回收类型 - * -XX:+UseG1GC - * 5.指定错误日日志的记录 - * -XX:ErrorFile=./hs_err_pid%p.log - * -XX:ErrorFile=./hs_err_pid.log - * 示例: - * -Xms10m - * -Xmx10m - * -XX:+UseG1GC - * -XX:+PrintGCDetails - * -Xloggc:var\log\gclog.log - * -XX:+HeapDumpOnOutOfMemoryError - * -XX:HeapDumpPath=var\log\ - * - * - * -verbose:gc - * -XX:+PrintGCDetails - * -XX:+PrintGCDateStamps - * -XX:+PrintGCTimeStamps - * -XX:+UseGCLogFileRotation - * -XX:NumberOfGCLogFiles=10 - * -XX:GCLogFileSize=100M + * 1.设置最大/小 heap + * -Xmx10m/-Xms10m + * 2.添加gc log + * -XX:+PrintGCDetails + * 3.添加gc记录文件 + * -Xloggc:文件名 + * 4.选择垃圾回收类型 + * -XX:+UseG1GC + * 5.指定错误日日志的记录 + * -XX:ErrorFile=./hs_err_pid%p.log + * -XX:ErrorFile=./hs_err_pid.log + * 示例: + * -Xms10m + * -Xmx10m + * -XX:+UseG1GC + * -XX:+PrintGCDetails + * -Xloggc:var\log\gclog.log + * -XX:+HeapDumpOnOutOfMemoryError + * -XX:HeapDumpPath=var\log\ + *

+ *

+ * -verbose:gc + * -XX:+PrintGCDetails + * -XX:+PrintGCDateStamps + * -XX:+PrintGCTimeStamps + * -XX:+UseGCLogFileRotation + * -XX:NumberOfGCLogFiles=10 + * -XX:GCLogFileSize=100M * * @param args * @throws InterruptedException @@ -51,7 +51,7 @@ public static void main(String[] args) throws InterruptedException { System.out.println("start......"); //Thread.sleep(1000000); List list = new ArrayList<>(); - while (true){ + while (true) { list.add("Jvm"); } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/JettyWebServerFactory.java b/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/JettyWebServerFactory.java index 9486ed9..7ecb263 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/JettyWebServerFactory.java +++ b/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/JettyWebServerFactory.java @@ -11,7 +11,7 @@ * @version 1.0.0 * @since 2020-09-14 */ -public class JettyWebServerFactory implements ServerFactory{ +public class JettyWebServerFactory implements ServerFactory { @Override public T create(int port) { return null; diff --git a/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/ServerFactory.java b/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/ServerFactory.java index 8d468e6..9355686 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/ServerFactory.java +++ b/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/ServerFactory.java @@ -17,8 +17,9 @@ public interface ServerFactory { /** *

- * 创建 + * 创建 *

+ * * @param port * @return void */ @@ -26,8 +27,9 @@ public interface ServerFactory { /** *

- * 启动容器 + * 启动容器 *

+ * * @param * @return void */ @@ -35,8 +37,9 @@ public interface ServerFactory { /** *

- * 定制容器 + * 定制容器 *

+ * * @param * @return void */ @@ -44,8 +47,9 @@ public interface ServerFactory { /** *

- * 销毁容器 + * 销毁容器 *

+ * * @param * @return void */ @@ -53,26 +57,28 @@ public interface ServerFactory { /** * 判断容器是否创建成功 + * * @param bean * @param * @throws ServerException */ - static void isNull(T bean) throws ServerException { - if(Objects.isNull(bean)){ - throw new ServerException("create server exception"); - } - } + static void isNull(T bean) throws ServerException { + if (Objects.isNull(bean)) { + throw new ServerException("create server exception"); + } + } /** *

- * 同于 + * 同于 *

+ * * @param * @return void */ - default void after(){ - this.stop(); - this.destroy(); - } + default void after() { + this.stop(); + this.destroy(); + } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/TomcatWebServerFactory.java b/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/TomcatWebServerFactory.java index fa8661b..d1dcc66 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/TomcatWebServerFactory.java +++ b/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/TomcatWebServerFactory.java @@ -15,11 +15,12 @@ * @version 1.0.0 * @since 2020-09-14 */ -public class TomcatWebServerFactory implements ServerFactory{ +public class TomcatWebServerFactory implements ServerFactory { Logger logger = LoggerFactory.getLogger(TomcatWebServerFactory.class); private Tomcat tomcat; + @SneakyThrows @Override public Tomcat create(int port) { @@ -32,7 +33,7 @@ public Tomcat create(int port) { @Override public void start() { logger.info("------start------"); - logger.info("------"+tomcat.getPort()+"------"); + logger.info("------" + tomcat.getPort() + "------"); logger.info("------start------"); } diff --git a/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/bean/Tomcat.java b/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/bean/Tomcat.java index 7499f43..77bb05c 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/bean/Tomcat.java +++ b/source-code/src/main/java/com/javayh/advanced/java/patterns/factory/bean/Tomcat.java @@ -31,8 +31,8 @@ public void setPort(int port) { this.port = port; } - private void assertParam(int port){ - if(port <= 0){ + private void assertParam(int port) { + if (port <= 0) { throw new IllegalArgumentException(); } } diff --git a/source-code/src/main/java/com/javayh/advanced/java/stream/StreamTest.java b/source-code/src/main/java/com/javayh/advanced/java/stream/StreamTest.java index 496223e..97d143a 100644 --- a/source-code/src/main/java/com/javayh/advanced/java/stream/StreamTest.java +++ b/source-code/src/main/java/com/javayh/advanced/java/stream/StreamTest.java @@ -16,32 +16,31 @@ * @version 1.0.0 * @since 2020-07-17 */ -public class StreamTest -{ +public class StreamTest { public static void main(String[] args) { //java Stream // 获取指定元素的流 - Stream stream = Stream.of("S0337", "S0ZOM", "S0ZP1","S0ZOM"); + Stream stream = Stream.of("S0337", "S0ZOM", "S0ZP1", "S0ZOM"); // 将指定的流转换成集合 Collectors 详细解说请看这里 List collect = stream.collect(Collectors.toList()); - System.out.println("集合为:"+collect); + System.out.println("集合为:" + collect); //数据过滤,同if(){}相同 List s0337 = collect.stream(). filter("S0337"::equalsIgnoreCase) .collect(Collectors.toList()); - System.out.println("数据过滤:"+s0337); + System.out.println("数据过滤:" + s0337); //去重 List distinct = collect.stream().distinct().collect(Collectors.toList()); - System.out.println("数据去重:"+distinct); + System.out.println("数据去重:" + distinct); //排序 List sorted = collect.stream().sorted().collect(Collectors.toList()); - System.out.println("数据排序一:"+distinct); + System.out.println("数据排序一:" + distinct); //根据指定字段排序 List entity = Stream.of(new StreamData("Yang", "28"), @@ -50,16 +49,16 @@ public static void main(String[] args) { List entitySorted = entity.stream() .sorted(Comparator.comparing(StreamData::getCode)) .collect(Collectors.toList()); - System.out.println("数据排序二:"+entitySorted.toString()); + System.out.println("数据排序二:" + entitySorted.toString()); //map List map = collect.stream().map(s -> s.replaceAll("S", "Y")).collect(Collectors.toList()); List mapEntity = entitySorted.stream().map(StreamData::getCode).collect(Collectors.toList()); - System.out.println("map:"+map); - System.out.println("mapEntity:"+mapEntity); + System.out.println("map:" + map); + System.out.println("mapEntity:" + mapEntity); List flatMap = collect.stream().flatMap(s -> Arrays.stream(s.split("0"))).collect(Collectors.toList()); - System.out.println("flatMap:"+flatMap); + System.out.println("flatMap:" + flatMap); //综合示例 List stringList = collect @@ -68,41 +67,41 @@ public static void main(String[] args) { .filter("S0337"::equalsIgnoreCase) .sorted(Comparator.comparing(String::hashCode)) .collect(Collectors.toList()); - System.out.println("综合示例:"+stringList); + System.out.println("综合示例:" + stringList); //获取集合第一个元素 Optional first = collect.stream().findFirst(); - System.out.println("第一个元素"+first.get()); + System.out.println("第一个元素" + first.get()); Optional any = collect.stream().findAny(); - System.out.println("第一个元素"+any.get()); + System.out.println("第一个元素" + any.get()); //提前查看数据 List peek = collect.stream().peek(System.out::println).collect(Collectors.toList()); //取指定的条数 List limit = collect.stream().limit(2).collect(Collectors.toList()); - System.out.println("limit:"+limit); + System.out.println("limit:" + limit); //返回指定下标后的元素 List skip = collect.stream().skip(1).collect(Collectors.toList()); - System.out.println("skip:"+skip); + System.out.println("skip:" + skip); //获取 size //以下代码 等同于 collect.size() long count = collect.stream().count(); - System.out.println("size:"+count); + System.out.println("size:" + count); //最大值 最小值同理 Optional max = collect.stream().max(Comparator.comparing(s -> s)); Optional maxEntity = entitySorted.stream().max(Comparator.comparing(StreamData::getCode)); - System.out.println("max值:"+max); - System.out.println("maxEntity值:"+maxEntity); + System.out.println("max值:" + max); + System.out.println("maxEntity值:" + maxEntity); } } -class StreamData{ +class StreamData { private String name; private String code; diff --git a/source-code/src/main/java/com/javayh/advanced/limiter/AutoIdempotent.java b/source-code/src/main/java/com/javayh/advanced/limiter/AutoIdempotent.java index d5cea28..f4931ba 100644 --- a/source-code/src/main/java/com/javayh/advanced/limiter/AutoIdempotent.java +++ b/source-code/src/main/java/com/javayh/advanced/limiter/AutoIdempotent.java @@ -7,7 +7,7 @@ /** *

- * 限流注解 + * 限流注解 *

* * @author Dylan diff --git a/source-code/src/main/java/com/javayh/advanced/limiter/LimiterTokenService.java b/source-code/src/main/java/com/javayh/advanced/limiter/LimiterTokenService.java index d8201d1..0bc6994 100644 --- a/source-code/src/main/java/com/javayh/advanced/limiter/LimiterTokenService.java +++ b/source-code/src/main/java/com/javayh/advanced/limiter/LimiterTokenService.java @@ -13,29 +13,32 @@ public interface LimiterTokenService { /** *

- * 创建token + * 创建token *

- * @version 1.0.0 - * @since 12/3/2020 + * * @param * @return java.lang.String + * @version 1.0.0 + * @since 12/3/2020 */ String createLimiterToken(); - + /** *

- * 校验token的合法性 + * 校验token的合法性 *

+ * + * @param token value + * @param time 设置过期时间 + * @return boolean * @version 1.0.0 * @since 12/3/2020 - * @param token value - * @param time 设置过期时间 - * @return boolean */ - boolean checkToken(String token,Long time); + boolean checkToken(String token, Long time); /** * 设置过期时间 + * * @param token */ void addTokenTime(String token); diff --git a/source-code/src/main/java/com/javayh/advanced/limiter/LimiterTokenServiceImpl.java b/source-code/src/main/java/com/javayh/advanced/limiter/LimiterTokenServiceImpl.java index 6871453..b90e236 100644 --- a/source-code/src/main/java/com/javayh/advanced/limiter/LimiterTokenServiceImpl.java +++ b/source-code/src/main/java/com/javayh/advanced/limiter/LimiterTokenServiceImpl.java @@ -15,7 +15,7 @@ * @since 2020-12-03 5:24 PM */ @Service -public class LimiterTokenServiceImpl implements LimiterTokenService{ +public class LimiterTokenServiceImpl implements LimiterTokenService { /** * 生成token @@ -30,14 +30,15 @@ public String createLimiterToken() { /** * 校验当前token是否被锁定 true: 锁定 | false: 未锁定 + * * @param token * @return */ @Override - public boolean checkToken(String token ,Long time) { + public boolean checkToken(String token, Long time) { Long l = System.currentTimeMillis(); Long cache = LocalCacheMap.getCache(token); - if(Objects.nonNull(cache)){ + if (Objects.nonNull(cache)) { if (l - cache > time) { return true; } @@ -52,12 +53,13 @@ public boolean checkToken(String token ,Long time) { /** * 添加时间 * 这一步是为模拟过期时间 + * * @param token key */ @Override public void addTokenTime(String token) { // 放入第一次的请求时间 long millis = System.currentTimeMillis(); - LocalCacheMap.setCache(token,millis); + LocalCacheMap.setCache(token, millis); } } diff --git a/source-code/src/main/java/com/javayh/advanced/limiter/LocalCacheMap.java b/source-code/src/main/java/com/javayh/advanced/limiter/LocalCacheMap.java index 0d20ac4..09a0f5f 100644 --- a/source-code/src/main/java/com/javayh/advanced/limiter/LocalCacheMap.java +++ b/source-code/src/main/java/com/javayh/advanced/limiter/LocalCacheMap.java @@ -14,40 +14,43 @@ */ public class LocalCacheMap { - private final static ConcurrentHashMap LOCAL_CACHE_MAP - = new ConcurrentHashMap<>(256); + private final static ConcurrentHashMap LOCAL_CACHE_MAP + = new ConcurrentHashMap<>(256); /** * 锁定 + * * @param key key * @param value 值 */ - public static void setCache(String key,Long value){ - LOCAL_CACHE_MAP.put(key,value); + public static void setCache(String key, Long value) { + LOCAL_CACHE_MAP.put(key, value); } /** * 检验是否讯在 + * * @param key * @return */ - public static Long getCache(String key){ + public static Long getCache(String key) { return LOCAL_CACHE_MAP.get(key); } /** * 删除cache + * * @param key * @return */ - public static boolean remove(String key){ + public static boolean remove(String key) { try { LOCAL_CACHE_MAP.remove(key); - }catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); return false; } - return true; + return true; } } diff --git a/source-code/src/main/java/com/javayh/advanced/mybatis/mapper/TestMapper.java b/source-code/src/main/java/com/javayh/advanced/mybatis/mapper/TestMapper.java index d82e51f..1ba2271 100644 --- a/source-code/src/main/java/com/javayh/advanced/mybatis/mapper/TestMapper.java +++ b/source-code/src/main/java/com/javayh/advanced/mybatis/mapper/TestMapper.java @@ -8,7 +8,7 @@ /** *

- * Mybatis + * Mybatis *

* * @author hai ji @@ -20,13 +20,14 @@ public interface TestMapper { /** *

- * 查询所有数据并且进行json处理 + * 查询所有数据并且进行json处理 *

+ * + * @param + * @return java.util.List * @version 1.0.0 * @author hai ji * @since 2020/8/4 - * @param - * @return java.util.List */ List findAll(); diff --git a/source-code/src/main/java/com/javayh/advanced/spring/aop/SysLog.java b/source-code/src/main/java/com/javayh/advanced/spring/aop/SysLog.java index 41ec01d..c807217 100644 --- a/source-code/src/main/java/com/javayh/advanced/spring/aop/SysLog.java +++ b/source-code/src/main/java/com/javayh/advanced/spring/aop/SysLog.java @@ -7,6 +7,7 @@ /** * log + * * @author haiyang */ @Target(ElementType.METHOD) diff --git a/source-code/src/main/java/com/javayh/advanced/spring/aop/SysLogAspect.java b/source-code/src/main/java/com/javayh/advanced/spring/aop/SysLogAspect.java index d06efba..a17d84f 100644 --- a/source-code/src/main/java/com/javayh/advanced/spring/aop/SysLogAspect.java +++ b/source-code/src/main/java/com/javayh/advanced/spring/aop/SysLogAspect.java @@ -29,7 +29,7 @@ @Order(-1) public class SysLogAspect { - private Map limiter = new ConcurrentHashMap<>(256); + private Map limiter = new ConcurrentHashMap<>(256); private final HttpServletRequest request; @@ -45,27 +45,26 @@ public Object getLog(ProceedingJoinPoint joinPoint, SysLog sysLog) throws Throwa proceed = joinPoint.proceed(); time = System.currentTimeMillis() - time; return proceed; - } - catch (Throwable throwable) { + } catch (Throwable throwable) { throw throwable; - } - finally { + } finally { // 方法执行后 - postOperation(joinPoint,time); + postOperation(joinPoint, time); } } /** *

- * 方法执行完之后的操作 + * 方法执行完之后的操作 *

- * @version 1.0.0 - * @author hai ji - * @since 2020/8/11 + * * @param joinPoint * @param time * @return void + * @version 1.0.0 + * @author hai ji + * @since 2020/8/11 */ private void postOperation(ProceedingJoinPoint joinPoint, long time) { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); @@ -78,55 +77,55 @@ private void postOperation(ProceedingJoinPoint joinPoint, long time) { long limit = annotation.limit(); inputCheckLimit(limit); //首先去缓存根据key 取value - if(limiter.get(limitKey) != null){ + if (limiter.get(limitKey) != null) { AtomicLong atomicLong1 = limiter.get(limitKey); long li = atomicLong1.get(); - if(li > 0){ + if (li > 0) { log.info("当前访问访问次数 : {}", atomicLong1); atomicLong1.decrementAndGet(); limiter.put(limitKey, atomicLong1); log.info("剩余访问访问次数 : {}", atomicLong1); - }else { - limiter(li,limitKey); + } else { + limiter(li, limitKey); } - }else { + } else { AtomicLong atomicLong = new AtomicLong(limit); - log.info("当前访问访问次数 : {}",atomicLong.get()); + log.info("当前访问访问次数 : {}", atomicLong.get()); //减少范文次数 atomicLong.decrementAndGet(); - limiter.put(limitKey,atomicLong); - log.info("剩余访问访问次数 : {}",atomicLong.get()); + limiter.put(limitKey, atomicLong); + log.info("剩余访问访问次数 : {}", atomicLong.get()); } - log.info(value+"执行耗时: {} s",time); + log.info(value + "执行耗时: {} s", time); } protected void inputCheckLimit(long limit) { - if(limit < 0){ + if (limit < 0) { throw new RuntimeException("Current limiting times must be greater than 0"); } } - protected void limiter(Long lo,String limitKey){ - if(lo <= 0){ + protected void limiter(Long lo, String limitKey) { + if (lo <= 0) { //根据key删除 limiter.remove(limitKey); - log.error(getIpAddr() +" The visit is too frequent. Please try again later"); + log.error(getIpAddr() + " The visit is too frequent. Please try again later"); throw new RuntimeException("The visit is too frequent. Please try again later"); } } private String getIpAddr() { String ip = request.getHeader("x-forwarded-for"); - if(ip ==null || ip.length() ==0 || "unknown".equalsIgnoreCase(ip)) { + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } - if(ip ==null || ip.length() ==0 || "unknown".equalsIgnoreCase(ip)) { + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } - if(ip ==null || ip.length() ==0 || "unknown".equalsIgnoreCase(ip)) { + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } - if("0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)){ + if ("0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)) { ip = "127.0.0.1"; } return ip; diff --git a/source-code/src/main/java/com/javayh/advanced/spring/bean/BaseBean.java b/source-code/src/main/java/com/javayh/advanced/spring/bean/BaseBean.java index 2fc01f8..37e221a 100644 --- a/source-code/src/main/java/com/javayh/advanced/spring/bean/BaseBean.java +++ b/source-code/src/main/java/com/javayh/advanced/spring/bean/BaseBean.java @@ -6,7 +6,7 @@ /** *

- * 测试 factory bean + * 测试 factory bean *

* * @author hai ji diff --git a/source-code/src/main/java/com/javayh/advanced/spring/bean/FactoryBeanLearn.java b/source-code/src/main/java/com/javayh/advanced/spring/bean/FactoryBeanLearn.java index a97e69f..bdd4717 100644 --- a/source-code/src/main/java/com/javayh/advanced/spring/bean/FactoryBeanLearn.java +++ b/source-code/src/main/java/com/javayh/advanced/spring/bean/FactoryBeanLearn.java @@ -26,9 +26,9 @@ * @since 2020-09-02 */ @Configuration -public class FactoryBeanLearn implements FactoryBean,InitializingBean { +public class FactoryBeanLearn implements FactoryBean, InitializingBean { - Logger log = LoggerFactory.getLogger(FactoryBeanLearn.class); + Logger log = LoggerFactory.getLogger(FactoryBeanLearn.class); private BaseBean baseBean; @@ -36,12 +36,12 @@ public class FactoryBeanLearn implements FactoryBean,InitializingBean public FactoryBeanLearn(CustomConfigurationProperties customConfigurationProperties) { this.customConfigurationProperties = customConfigurationProperties; - log.info("customConfigurationProperties init : {}",customConfigurationProperties.toString()); + log.info("customConfigurationProperties init : {}", customConfigurationProperties.toString()); } @Override public BaseBean getObject() throws Exception { - if(Objects.isNull(baseBean)){ + if (Objects.isNull(baseBean)) { this.afterPropertiesSet(); } return this.baseBean; @@ -65,13 +65,14 @@ public void afterPropertiesSet() throws Exception { /** *

- * 实例化对象 + * 实例化对象 *

+ * * @param * @return com.javayh.advanced.spring.bean.BaseBean */ private BaseBean buildBaseBean() { - if (Objects.isNull(customConfigurationProperties)){ + if (Objects.isNull(customConfigurationProperties)) { throw new RuntimeException("customConfigurationProperties is null"); } return BaseBean.builder() diff --git a/source-code/src/main/java/com/javayh/advanced/spring/transaction/TransactionTest.java b/source-code/src/main/java/com/javayh/advanced/spring/transaction/TransactionTest.java index 9810adf..536a99b 100644 --- a/source-code/src/main/java/com/javayh/advanced/spring/transaction/TransactionTest.java +++ b/source-code/src/main/java/com/javayh/advanced/spring/transaction/TransactionTest.java @@ -25,14 +25,14 @@ public class TransactionTest { private TransactionTest2 transactionTest2; @Transactional(rollbackFor = Exception.class) - public void test01(){ + public void test01() { testMapper.insert("789"); transactionTest2.test02(); //test02(); } @Transactional(rollbackFor = Exception.class) - public void test02(){ + public void test02() { testMapper.insert("12345"); Integer.valueOf("1245i"); } diff --git a/source-code/src/main/java/com/javayh/advanced/spring/transaction/TransactionTest2.java b/source-code/src/main/java/com/javayh/advanced/spring/transaction/TransactionTest2.java index 6a1077d..7fe84aa 100644 --- a/source-code/src/main/java/com/javayh/advanced/spring/transaction/TransactionTest2.java +++ b/source-code/src/main/java/com/javayh/advanced/spring/transaction/TransactionTest2.java @@ -21,13 +21,13 @@ public class TransactionTest2 { private TestMapper testMapper; @Transactional(rollbackFor = Exception.class) - public void test01(){ + public void test01() { testMapper.insert("789"); test02(); } //@Transactional(rollbackFor = Exception.class) - public void test02(){ + public void test02() { testMapper.insert("12345"); Integer.valueOf("1245i"); } diff --git a/source-code/src/main/java/com/javayh/advanced/spring/web/TestWeb.java b/source-code/src/main/java/com/javayh/advanced/spring/web/TestWeb.java index fae4dc7..6f69428 100644 --- a/source-code/src/main/java/com/javayh/advanced/spring/web/TestWeb.java +++ b/source-code/src/main/java/com/javayh/advanced/spring/web/TestWeb.java @@ -16,9 +16,9 @@ public class TestWeb { @AutoIdempotent @SneakyThrows - @SysLog(value = "测试Aop注解",limit = 3) + @SysLog(value = "测试Aop注解", limit = 3) @RequestMapping(value = "syslog") - public String test(){ + public String test() { Thread.sleep(5000); return "test"; } diff --git a/source-code/src/main/java/com/javayh/advanced/util/UnsafeUtils.java b/source-code/src/main/java/com/javayh/advanced/util/UnsafeUtils.java index dd1fa46..95f0f48 100644 --- a/source-code/src/main/java/com/javayh/advanced/util/UnsafeUtils.java +++ b/source-code/src/main/java/com/javayh/advanced/util/UnsafeUtils.java @@ -21,14 +21,15 @@ public class UnsafeUtils { /** *

- * 通过反射获取 Unsafe + * 通过反射获取 Unsafe *

+ * + * @return sun.misc.Unsafe * @version 1.0.0 * @author hai ji * @since 2020/8/11 - * @return sun.misc.Unsafe */ - public static Unsafe getUnsafe(){ + public static Unsafe getUnsafe() { try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); diff --git a/source-code/src/main/resources/mapper/test/TestMapper.xml b/source-code/src/main/resources/mapper/test/TestMapper.xml index 6dd1202..6f35a2d 100644 --- a/source-code/src/main/resources/mapper/test/TestMapper.xml +++ b/source-code/src/main/resources/mapper/test/TestMapper.xml @@ -7,12 +7,12 @@ - + - + @@ -22,26 +22,26 @@