diff --git a/01jvm/GCLearning.md b/01jvm/GCLearning.md
new file mode 100644
index 00000000..f0a775a9
--- /dev/null
+++ b/01jvm/GCLearning.md
@@ -0,0 +1,107 @@
+## SerialGC
+
+配置命令:-XX:+UseSerialGC
+
+串行GC对年轻代使用mark-copy(标记-复制)算法,对老年代使用mark-sweep-compact(标记-清除-整理)算法。
+
+特点:单线程GC,GC时会stop-the-world(STW),停止应用线程,只适合几百MB堆内存的JVM,单核CPU时比较有用。年轻代默认分配内存-1/3堆内存左右,老年代默认分配内存-2/3堆内存左右。
+
+通过作业1可以看出当堆内存变大时,串行GC收集的频率下降了,但是每一次收集所用的时间有所增加,会增加STW的时间,系统延迟增加,所以串行GC不适合占用内存很大的系统。
+
+-XX:+UseParNewGC改进版本的SerialGC(并行回收年轻代),可以配合CMS使用。
+
+---
+## Parallel GC
+
+配置命令:
+-XX:+UseParallelGC
+-XX:+UseParallelOldGC
+-XX:+UseParallelGC -XX:+UseParallelOldGC
+
+并行GC在年轻代使用标记-复制(mark-copy)算法,在老年代使用标记-清除-整理(mark-sweep-compact)算法。
+
+特点:多线程GC(并行GC),GC同样会STW,适用于多核服务器,主要目标是增加吞吐量。
++ 在GC期间,所有CPU内核(应该是JVM拥有的内核吧?)都在并行清理垃圾,所以总暂停时间更短;
++ 在两次GC周期的间隔期,没有GC线程在运行,不会消耗任何系统资源
+
+通过作业1可以看出并行GC进行一次垃圾收集的时间要明显少于串行GC,在堆内存较大时能比串行GC条件下生成更多的对象,有更高的吞吐量。
+
+---
+## CMS GC
+### Mostly Concurrent Mark and Sweep Garbage Collector
+
+配置命令: -XX:+UseConcMarkSweepGC
+
+CMS GC对年轻代采用(ParNew)并行STW方式的mark-copy(标记-复制)算法,对老年代主要使用mark-sweep(标记-清除)算法。
+
+目标:避免在老年代垃圾收集时出现长时间的卡顿
+特点:
++ 不对老年代进行整理,而是使用空闲列表(free-lists)来管理内存空间的回收
++ 在mark-and-sweep(标记-清除)阶段的大部分工作和应用线程一起并发执行。
++ 默认情况下,CMS使用的并发线程数等于CPU核心数的1/4。
++ 进行老年代的并发回收时,可能会伴随着多次年轻代的minorGC。
+
+处理过程:
+1. Initial Mark(初始标记)。伴随STW暂停,初始标记的目标是标记所有的根对象,包括根对象直接引用的对象,以及被年轻代中所有存活对象所引用的对象(老年代单独回收)
+2. Concurrent Mark(并发标记)。CMS GC遍历老年代,标记所有的存活对象。
+3. Concurrent Preclean(并发预清理)。如果在并发标记的过程中引用关系发生了变化,JVM会通过"Card(卡片)"的方式将发生了改变的区域标记成"脏"区,这就是所谓的卡片标记(Card Marking)
+4. Final Remark(最终标记)。伴随STW,完成老年代中所有存活对象的标记。
+5. Concurrent Sweep(并发清除)
+6. Concurrent Reset(并发重置) 删除不再使用的对象,并回收他们占用的内存空间
+
+存在问题:老年代内存碎片问题(因为不压缩),在某些情况下GC会造成不可预测的暂停时间,特别是堆内存较大的情况下。
+
+最大young区大小:
+ParallelGC:1024M/3 = 341.3M
+CMS: 64M\*GC线程数4\*13/10 = 332.8M
+
+通过作业1的观察,CMS GC在Final Remark之前可能会做几次年轻代的回收,以提高Final Remark的效率。同时如果GC无法处理产生过快的垃圾,会发生concurrent mode failure,此时所有应用线程会被暂停,CMS GC发生退化。
+
+---
+
+## G1 GC
+### Garbage-First
+
+配置命令: -XX:+UseG1GC -XX:MaxGCPauseMillis=50
+
+目标:将STW停顿的时间和分布,变成可预期且可配置的。(启发性配置?)
+
+特点:
++ G1 GC的堆内存不再分成年轻代和老年代,而是划分成多个(通常是2048个)可以存放对象的小块堆区域(smaller heap regions)。
++ 增量收集垃圾。每次GC暂停都会收集所有年轻代的内存块,但一般只包含部分老年代的内存块。
+
+重要配置参数:
++ -XX:G1NewSizePercent:初始年轻代占整个 Java Heap 的大小,默认值为 5%
++ -XX:G1MaxNewSizePercent:最大年轻代占整个 Java Heap 的大小,默认值为 60%;
++ -XX:G1HeapRegionSize:设置每个 Region 的大小,单位 MB,需要为 1、2、4、8、16、32 中的某个值,默认是堆内存的1/2000。如果这个值设置比较大,那么大对象就可以进入 Region 了;
++ -XX:ConcGCThreads:与 Java 应用一起执行的 GC 线程数量,默认是 Java 线程的 1/4,减少这个参数的数值可能会提升并行回收的效率,提高系统内部吞吐量。如果这个数值过低,参与回收垃圾的线程不足,也会导致并行回收机制耗时加长;
++ -XX:+InitiatingHeapOccupancyPercent(简称 IHOP):G1 内部并行回收循环启动的阈值,默认为 Java Heap的 45%。这个可以理解为老年代使用大于等于 45% 的时候,JVM 会启动垃圾回收。这个值非常重要,它决定了在什么时间启动老年代的并行回收;
++ -XX:G1HeapWastePercent:G1停止回收的最小内存大小,默认是堆大小的 5%。GC 会收集所有的 Region 中的对象,但是如果下降到了 5%,就会停下来不再收集了。就是说,不必每次回收就把所有的垃圾都处理完,可以遗留少量的下次处理,这样也降低了单次消耗的时间;
++ -XX:+GCTimeRatio:这个参数就是计算花在 Java 应用线程上和花在 GC 线程上的时间比率,默认是 9,跟新生代内存的分配比例一致。这个参数主要的目的是让用户可以控制花在应用上的时间,G1 的计算公式是 100/(1+GCTimeRatio)。这样如果参数设置为9,则最多 10% 的时间会花在 GC 工作上面。Parallel GC 的默认值是 99,表示 1% 的时间被用在 GC 上面,这是因为 Parallel GC 贯穿整个 GC,而 G1 则根据 Region 来进行划分,不需要全局性扫描整个内存堆.
++ -XX:MaxGCPauseMills:预期 G1 每次执行 GC 操作的暂停时间,单位是毫秒,默认值是 200 毫秒,G1 会尽量保证控制在这个范围内。
+
+处理过程
+1. 年轻代模式转移暂停(Evacuation Pause):
+2. 并发标记(Concurrent Marking):过程基本与CMS一样
+ + Phase1:Initial Mark(初始标记)
+ + Phase2:Root Region Scan(Root区扫描)
+ + Phase3:Concurrent Mark(并发标记)
+ + Phase4:Remark(再次标记)
+ + Phase5:Cleanup(清理)
+3. 转移暂停: 混合模式(Evacuation Pause (mixed))
+
+G1 GC触发Full GC的三种情况(退化成Serial GC)
+1. 并发模式失败。
+解决办法
+ 增加堆大小,或者调整周期
+2. 晋升失败
+解决办法
++ 增加 –XX:G1ReservePercent 选项的值(并相应增加总的堆大小)增加预留内存量。
++ 通过减少 –XX:InitiatingHeapOccupancyPercent 提前启动标记周期。
++ 增加 –XX:ConcGCThreads 选项的值来增加并行标记线程的数目。
+3. 巨型对象分配失败
+解决办法 增加内存或者增大 -XX:G1HeapRegionSize
+
+通过作业1的观察,混合模式的转移暂停不一定紧跟并发标记阶段。在并发标记与混合转移暂停之间,可能存在多次young模式的转移暂停,并且混合模式的转移暂停在一次并发标记后会发生多次。
+
+---
\ No newline at end of file
diff --git a/02nio/nio02/src/main/java/io/github/kimmking/gateway/filter/MyHttpRequestFilter.java b/02nio/nio02/src/main/java/io/github/kimmking/gateway/filter/MyHttpRequestFilter.java
new file mode 100644
index 00000000..c5414609
--- /dev/null
+++ b/02nio/nio02/src/main/java/io/github/kimmking/gateway/filter/MyHttpRequestFilter.java
@@ -0,0 +1,4 @@
+package io.github.kimmking.gateway.filter;
+
+public class MyHttpRequestFilter {
+}
diff --git a/02nio/okhttpdemo/okhttpdemo/src/main/java/com/geekbang/okhttpdemo/work/OkHttpDemo.java b/02nio/okhttpdemo/okhttpdemo/src/main/java/com/geekbang/okhttpdemo/work/OkHttpDemo.java
new file mode 100644
index 00000000..a635ec4d
--- /dev/null
+++ b/02nio/okhttpdemo/okhttpdemo/src/main/java/com/geekbang/okhttpdemo/work/OkHttpDemo.java
@@ -0,0 +1,28 @@
+package com.geekbang.okhttpdemo.work;
+
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import java.io.IOException;
+
+public class OkHttpDemo {
+ final OkHttpClient client = new OkHttpClient();
+
+ String getUrl(String url) throws IOException {
+ Request request = new Request.Builder()
+ .url(url)
+ .build();
+
+ try (Response response = client.newCall(request).execute()) {
+ return response.body().string();
+ }
+ }
+
+
+ public static void main(String[] args) throws IOException {
+ OkHttpDemo okHttpDemo = new OkHttpDemo();
+ String response = okHttpDemo.getUrl("http://localhost:8801");
+ System.out.println(response);
+ }
+}
diff --git a/02nio/workforweek2/GCLearning.md b/02nio/workforweek2/GCLearning.md
new file mode 100644
index 00000000..f0a775a9
--- /dev/null
+++ b/02nio/workforweek2/GCLearning.md
@@ -0,0 +1,107 @@
+## SerialGC
+
+配置命令:-XX:+UseSerialGC
+
+串行GC对年轻代使用mark-copy(标记-复制)算法,对老年代使用mark-sweep-compact(标记-清除-整理)算法。
+
+特点:单线程GC,GC时会stop-the-world(STW),停止应用线程,只适合几百MB堆内存的JVM,单核CPU时比较有用。年轻代默认分配内存-1/3堆内存左右,老年代默认分配内存-2/3堆内存左右。
+
+通过作业1可以看出当堆内存变大时,串行GC收集的频率下降了,但是每一次收集所用的时间有所增加,会增加STW的时间,系统延迟增加,所以串行GC不适合占用内存很大的系统。
+
+-XX:+UseParNewGC改进版本的SerialGC(并行回收年轻代),可以配合CMS使用。
+
+---
+## Parallel GC
+
+配置命令:
+-XX:+UseParallelGC
+-XX:+UseParallelOldGC
+-XX:+UseParallelGC -XX:+UseParallelOldGC
+
+并行GC在年轻代使用标记-复制(mark-copy)算法,在老年代使用标记-清除-整理(mark-sweep-compact)算法。
+
+特点:多线程GC(并行GC),GC同样会STW,适用于多核服务器,主要目标是增加吞吐量。
++ 在GC期间,所有CPU内核(应该是JVM拥有的内核吧?)都在并行清理垃圾,所以总暂停时间更短;
++ 在两次GC周期的间隔期,没有GC线程在运行,不会消耗任何系统资源
+
+通过作业1可以看出并行GC进行一次垃圾收集的时间要明显少于串行GC,在堆内存较大时能比串行GC条件下生成更多的对象,有更高的吞吐量。
+
+---
+## CMS GC
+### Mostly Concurrent Mark and Sweep Garbage Collector
+
+配置命令: -XX:+UseConcMarkSweepGC
+
+CMS GC对年轻代采用(ParNew)并行STW方式的mark-copy(标记-复制)算法,对老年代主要使用mark-sweep(标记-清除)算法。
+
+目标:避免在老年代垃圾收集时出现长时间的卡顿
+特点:
++ 不对老年代进行整理,而是使用空闲列表(free-lists)来管理内存空间的回收
++ 在mark-and-sweep(标记-清除)阶段的大部分工作和应用线程一起并发执行。
++ 默认情况下,CMS使用的并发线程数等于CPU核心数的1/4。
++ 进行老年代的并发回收时,可能会伴随着多次年轻代的minorGC。
+
+处理过程:
+1. Initial Mark(初始标记)。伴随STW暂停,初始标记的目标是标记所有的根对象,包括根对象直接引用的对象,以及被年轻代中所有存活对象所引用的对象(老年代单独回收)
+2. Concurrent Mark(并发标记)。CMS GC遍历老年代,标记所有的存活对象。
+3. Concurrent Preclean(并发预清理)。如果在并发标记的过程中引用关系发生了变化,JVM会通过"Card(卡片)"的方式将发生了改变的区域标记成"脏"区,这就是所谓的卡片标记(Card Marking)
+4. Final Remark(最终标记)。伴随STW,完成老年代中所有存活对象的标记。
+5. Concurrent Sweep(并发清除)
+6. Concurrent Reset(并发重置) 删除不再使用的对象,并回收他们占用的内存空间
+
+存在问题:老年代内存碎片问题(因为不压缩),在某些情况下GC会造成不可预测的暂停时间,特别是堆内存较大的情况下。
+
+最大young区大小:
+ParallelGC:1024M/3 = 341.3M
+CMS: 64M\*GC线程数4\*13/10 = 332.8M
+
+通过作业1的观察,CMS GC在Final Remark之前可能会做几次年轻代的回收,以提高Final Remark的效率。同时如果GC无法处理产生过快的垃圾,会发生concurrent mode failure,此时所有应用线程会被暂停,CMS GC发生退化。
+
+---
+
+## G1 GC
+### Garbage-First
+
+配置命令: -XX:+UseG1GC -XX:MaxGCPauseMillis=50
+
+目标:将STW停顿的时间和分布,变成可预期且可配置的。(启发性配置?)
+
+特点:
++ G1 GC的堆内存不再分成年轻代和老年代,而是划分成多个(通常是2048个)可以存放对象的小块堆区域(smaller heap regions)。
++ 增量收集垃圾。每次GC暂停都会收集所有年轻代的内存块,但一般只包含部分老年代的内存块。
+
+重要配置参数:
++ -XX:G1NewSizePercent:初始年轻代占整个 Java Heap 的大小,默认值为 5%
++ -XX:G1MaxNewSizePercent:最大年轻代占整个 Java Heap 的大小,默认值为 60%;
++ -XX:G1HeapRegionSize:设置每个 Region 的大小,单位 MB,需要为 1、2、4、8、16、32 中的某个值,默认是堆内存的1/2000。如果这个值设置比较大,那么大对象就可以进入 Region 了;
++ -XX:ConcGCThreads:与 Java 应用一起执行的 GC 线程数量,默认是 Java 线程的 1/4,减少这个参数的数值可能会提升并行回收的效率,提高系统内部吞吐量。如果这个数值过低,参与回收垃圾的线程不足,也会导致并行回收机制耗时加长;
++ -XX:+InitiatingHeapOccupancyPercent(简称 IHOP):G1 内部并行回收循环启动的阈值,默认为 Java Heap的 45%。这个可以理解为老年代使用大于等于 45% 的时候,JVM 会启动垃圾回收。这个值非常重要,它决定了在什么时间启动老年代的并行回收;
++ -XX:G1HeapWastePercent:G1停止回收的最小内存大小,默认是堆大小的 5%。GC 会收集所有的 Region 中的对象,但是如果下降到了 5%,就会停下来不再收集了。就是说,不必每次回收就把所有的垃圾都处理完,可以遗留少量的下次处理,这样也降低了单次消耗的时间;
++ -XX:+GCTimeRatio:这个参数就是计算花在 Java 应用线程上和花在 GC 线程上的时间比率,默认是 9,跟新生代内存的分配比例一致。这个参数主要的目的是让用户可以控制花在应用上的时间,G1 的计算公式是 100/(1+GCTimeRatio)。这样如果参数设置为9,则最多 10% 的时间会花在 GC 工作上面。Parallel GC 的默认值是 99,表示 1% 的时间被用在 GC 上面,这是因为 Parallel GC 贯穿整个 GC,而 G1 则根据 Region 来进行划分,不需要全局性扫描整个内存堆.
++ -XX:MaxGCPauseMills:预期 G1 每次执行 GC 操作的暂停时间,单位是毫秒,默认值是 200 毫秒,G1 会尽量保证控制在这个范围内。
+
+处理过程
+1. 年轻代模式转移暂停(Evacuation Pause):
+2. 并发标记(Concurrent Marking):过程基本与CMS一样
+ + Phase1:Initial Mark(初始标记)
+ + Phase2:Root Region Scan(Root区扫描)
+ + Phase3:Concurrent Mark(并发标记)
+ + Phase4:Remark(再次标记)
+ + Phase5:Cleanup(清理)
+3. 转移暂停: 混合模式(Evacuation Pause (mixed))
+
+G1 GC触发Full GC的三种情况(退化成Serial GC)
+1. 并发模式失败。
+解决办法
+ 增加堆大小,或者调整周期
+2. 晋升失败
+解决办法
++ 增加 –XX:G1ReservePercent 选项的值(并相应增加总的堆大小)增加预留内存量。
++ 通过减少 –XX:InitiatingHeapOccupancyPercent 提前启动标记周期。
++ 增加 –XX:ConcGCThreads 选项的值来增加并行标记线程的数目。
+3. 巨型对象分配失败
+解决办法 增加内存或者增大 -XX:G1HeapRegionSize
+
+通过作业1的观察,混合模式的转移暂停不一定紧跟并发标记阶段。在并发标记与混合转移暂停之间,可能存在多次young模式的转移暂停,并且混合模式的转移暂停在一次并发标记后会发生多次。
+
+---
\ No newline at end of file
diff --git a/02nio/workforweek2/OkHttpDemo.java b/02nio/workforweek2/OkHttpDemo.java
new file mode 100644
index 00000000..a635ec4d
--- /dev/null
+++ b/02nio/workforweek2/OkHttpDemo.java
@@ -0,0 +1,28 @@
+package com.geekbang.okhttpdemo.work;
+
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import java.io.IOException;
+
+public class OkHttpDemo {
+ final OkHttpClient client = new OkHttpClient();
+
+ String getUrl(String url) throws IOException {
+ Request request = new Request.Builder()
+ .url(url)
+ .build();
+
+ try (Response response = client.newCall(request).execute()) {
+ return response.body().string();
+ }
+ }
+
+
+ public static void main(String[] args) throws IOException {
+ OkHttpDemo okHttpDemo = new OkHttpDemo();
+ String response = okHttpDemo.getUrl("http://localhost:8801");
+ System.out.println(response);
+ }
+}
diff --git a/02nio/workforweek3/work1/HttpHandler.java b/02nio/workforweek3/work1/HttpHandler.java
new file mode 100644
index 00000000..a9e01f11
--- /dev/null
+++ b/02nio/workforweek3/work1/HttpHandler.java
@@ -0,0 +1,93 @@
+package java0.nio01.netty;
+
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.HttpUtil;
+import io.netty.util.ReferenceCountUtil;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import java.io.IOException;
+
+import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
+import static io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE;
+import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT;
+import static io.netty.handler.codec.http.HttpResponseStatus.OK;
+import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
+
+public class HttpHandler extends ChannelInboundHandlerAdapter {
+
+ final OkHttpClient CLIENT = new OkHttpClient();
+ final String TARGET_URL = "http://localhost:8801";
+
+ @Override
+ public void channelReadComplete(ChannelHandlerContext ctx) {
+ ctx.flush();
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) {
+ try {
+ //logger.info("channelRead流量接口请求开始,时间为{}", startTime);
+ FullHttpRequest fullRequest = (FullHttpRequest) msg;
+
+ handlerTest(fullRequest, ctx);
+
+ } catch(Exception e) {
+ e.printStackTrace();
+ } finally {
+ ReferenceCountUtil.release(msg);
+ }
+ }
+
+ private void handlerTest(FullHttpRequest fullRequest, ChannelHandlerContext ctx) {
+ FullHttpResponse response = null;
+ try {
+ String value = getUrl(TARGET_URL); // 对接上次作业的httpclient或者okhttp请求另一个url的响应数据
+
+// httpGet ... http://localhost:8801
+// 返回的响应,"hello,nio";
+// value = reponse....
+
+ response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(value.getBytes("UTF-8")));
+ response.headers().set("Content-Type", "application/json");
+ response.headers().setInt("Content-Length", response.content().readableBytes());
+
+ } catch (Exception e) {
+ System.out.println("处理出错:"+e.getMessage());
+ response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT);
+ } finally {
+ if (fullRequest != null) {
+ if (!HttpUtil.isKeepAlive(fullRequest)) {
+ ctx.write(response).addListener(ChannelFutureListener.CLOSE);
+ } else {
+ response.headers().set(CONNECTION, KEEP_ALIVE);
+ ctx.write(response);
+ }
+ ctx.flush();
+ }
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ cause.printStackTrace();
+ ctx.close();
+ }
+
+
+ String getUrl(String url) throws IOException {
+ Request request = new Request.Builder()
+ .url(url)
+ .build();
+ try (Response response = CLIENT.newCall(request).execute()) {
+ return response.body().string();
+ }
+ }
+}
diff --git a/02nio/workforweek3/work3/HttpRequestFilter.java b/02nio/workforweek3/work3/HttpRequestFilter.java
new file mode 100644
index 00000000..31253b40
--- /dev/null
+++ b/02nio/workforweek3/work3/HttpRequestFilter.java
@@ -0,0 +1,10 @@
+package io.github.kimmking.gateway.filter;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.FullHttpRequest;
+
+public interface HttpRequestFilter {
+
+ void filter(FullHttpRequest fullRequest, ChannelHandlerContext ctx);
+
+}
diff --git a/02nio/workforweek3/work3/MyHttpRequestFilter.java b/02nio/workforweek3/work3/MyHttpRequestFilter.java
new file mode 100644
index 00000000..77998b43
--- /dev/null
+++ b/02nio/workforweek3/work3/MyHttpRequestFilter.java
@@ -0,0 +1,12 @@
+package io.github.kimmking.gateway.filter;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.FullHttpRequest;
+
+public class MyHttpRequestFilter implements HttpRequestFilter {
+ @Override
+ public void filter(FullHttpRequest fullRequest, ChannelHandlerContext ctx) {
+ fullRequest.headers().set("User-Agent",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36");
+ }
+}
diff --git a/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method1.java b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method1.java
new file mode 100644
index 00000000..1011919e
--- /dev/null
+++ b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method1.java
@@ -0,0 +1,56 @@
+package java0.conc0303.homework.work2;
+
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+/**
+ * 本周作业:(必做)思考有多少种方式,在main函数启动一个新线程或线程池,
+ * 异步运行一个方法,拿到这个方法的返回值后,退出主线程?
+ * 写出你的方法,越多越好,提交到github。
+ *
+ * 一个简单的代码参考:
+ */
+public class Method1 {
+
+ public static void main(String[] args) {
+
+ long start=System.currentTimeMillis();
+
+ // 在这里创建一个线程或线程池,
+ // 异步执行 下面方法
+
+ FutureTask task = new FutureTask(new Callable() {
+ @Override
+ public Integer call() throws Exception {
+ return sum();
+ }
+ });
+
+ new Thread(task).start();
+ try {
+ // 确保 拿到result 并输出
+ System.out.println("异步计算结果为:"+task.get());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+
+
+ System.out.println("使用时间:"+ (System.currentTimeMillis()-start) + " ms");
+
+ // 然后退出main线程
+ }
+
+ private static int sum() {
+ return fibo(36);
+ }
+
+ private static int fibo(int a) {
+ if ( a < 2)
+ return 1;
+ return fibo(a-1) + fibo(a-2);
+ }
+}
diff --git a/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method2.java b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method2.java
new file mode 100644
index 00000000..31b5aa7c
--- /dev/null
+++ b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method2.java
@@ -0,0 +1,55 @@
+package java0.conc0303.homework.work2;
+
+import java.util.concurrent.*;
+
+/**
+ * 本周作业:(必做)思考有多少种方式,在main函数启动一个新线程或线程池,
+ * 异步运行一个方法,拿到这个方法的返回值后,退出主线程?
+ * 写出你的方法,越多越好,提交到github。
+ *
+ * 一个简单的代码参考:
+ */
+public class Method2 {
+
+ public static void main(String[] args) {
+
+ long start=System.currentTimeMillis();
+
+ // 在这里创建一个线程或线程池,
+ // 异步执行 下面方法
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ FutureTask task = new FutureTask(new Callable() {
+ @Override
+ public Integer call() throws Exception {
+ return sum();
+ }
+ });
+ executor.submit(task);
+
+ try {
+ // 确保 拿到result 并输出
+ System.out.println("异步计算结果为:"+task.get());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+
+
+ System.out.println("使用时间:"+ (System.currentTimeMillis()-start) + " ms");
+
+ // 然后退出main线程
+ executor.shutdown();
+ }
+
+ private static int sum() {
+ return fibo(36);
+ }
+
+ private static int fibo(int a) {
+ if ( a < 2)
+ return 1;
+ return fibo(a-1) + fibo(a-2);
+ }
+}
diff --git a/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method3.java b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method3.java
new file mode 100644
index 00000000..71d2f067
--- /dev/null
+++ b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method3.java
@@ -0,0 +1,41 @@
+package java0.conc0303.homework.work2;
+
+import java.util.concurrent.*;
+
+/**
+ * 本周作业:(必做)思考有多少种方式,在main函数启动一个新线程或线程池,
+ * 异步运行一个方法,拿到这个方法的返回值后,退出主线程?
+ * 写出你的方法,越多越好,提交到github。
+ *
+ * 一个简单的代码参考:
+ */
+public class Method3 {
+
+ public static void main(String[] args) {
+
+ long start=System.currentTimeMillis();
+
+ // 在这里创建一个线程或线程池,
+ // 异步执行 下面方法
+
+ int result = CompletableFuture.supplyAsync(()->{
+ return sum();
+ }).join();
+
+ System.out.println("异步计算结果为:"+result);
+ System.out.println("使用时间:"+ (System.currentTimeMillis()-start) + " ms");
+
+ // 然后退出main线程
+
+ }
+
+ private static int sum() {
+ return fibo(36);
+ }
+
+ private static int fibo(int a) {
+ if ( a < 2)
+ return 1;
+ return fibo(a-1) + fibo(a-2);
+ }
+}
diff --git a/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method4.java b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method4.java
new file mode 100644
index 00000000..0a99d7bb
--- /dev/null
+++ b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method4.java
@@ -0,0 +1,48 @@
+package java0.conc0303.homework.work2;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * 本周作业:(必做)思考有多少种方式,在main函数启动一个新线程或线程池,
+ * 异步运行一个方法,拿到这个方法的返回值后,退出主线程?
+ * 写出你的方法,越多越好,提交到github。
+ *
+ * 一个简单的代码参考:
+ */
+public class Method4 {
+ private static int result = 0;
+
+ public static void main(String[] args) throws InterruptedException {
+
+ long start=System.currentTimeMillis();
+
+ // 在这里创建一个线程或线程池,
+ // 异步执行 下面方法
+ Thread thread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ result = sum();
+ }
+ });
+
+ thread.start();
+
+ thread.join();
+
+ System.out.println("异步计算结果为:"+result);
+ System.out.println("使用时间:"+ (System.currentTimeMillis()-start) + " ms");
+
+ // 然后退出main线程
+
+ }
+
+ private static int sum() {
+ return fibo(36);
+ }
+
+ private static int fibo(int a) {
+ if ( a < 2)
+ return 1;
+ return fibo(a-1) + fibo(a-2);
+ }
+}
diff --git a/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method5.java b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method5.java
new file mode 100644
index 00000000..208e7a19
--- /dev/null
+++ b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method5.java
@@ -0,0 +1,55 @@
+package java0.conc0303.homework.work2;
+
+import java.util.concurrent.*;
+
+/**
+ * 本周作业:(必做)思考有多少种方式,在main函数启动一个新线程或线程池,
+ * 异步运行一个方法,拿到这个方法的返回值后,退出主线程?
+ * 写出你的方法,越多越好,提交到github。
+ *
+ * 一个简单的代码参考:
+ */
+public class Method5 {
+
+ public static void main(String[] args) {
+
+ long start=System.currentTimeMillis();
+
+ // 在这里创建一个线程或线程池,
+ // 异步执行 下面方法
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ CompletionService completionService = new ExecutorCompletionService<>(executor) ;
+ completionService.submit(new Callable() {
+ @Override
+ public Integer call() throws Exception {
+ return sum();
+ }
+ });
+
+ try {
+ // 确保 拿到result 并输出
+ System.out.println("异步计算结果为:"+completionService.take().get());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+
+
+ System.out.println("使用时间:"+ (System.currentTimeMillis()-start) + " ms");
+
+ // 然后退出main线程
+ executor.shutdown();
+ }
+
+ private static int sum() {
+ return fibo(36);
+ }
+
+ private static int fibo(int a) {
+ if ( a < 2)
+ return 1;
+ return fibo(a-1) + fibo(a-2);
+ }
+}
diff --git a/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method6.java b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method6.java
new file mode 100644
index 00000000..b426a1ad
--- /dev/null
+++ b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method6.java
@@ -0,0 +1,63 @@
+package java0.conc0303.homework.work2;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * 本周作业:(必做)思考有多少种方式,在main函数启动一个新线程或线程池,
+ * 异步运行一个方法,拿到这个方法的返回值后,退出主线程?
+ * 写出你的方法,越多越好,提交到github。
+ *
+ * 一个简单的代码参考:
+ */
+public class Method6 {
+
+ public static void main(String[] args) {
+
+ long start=System.currentTimeMillis();
+
+ // 在这里创建一个线程或线程池,
+ // 异步执行 下面方法
+
+ FiboRunnable fiboRunnable = new FiboRunnable();
+ Thread thread = new Thread(fiboRunnable);
+ thread.start();
+
+ try {
+ thread.join();
+ System.out.println(fiboRunnable.getResult());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+
+ System.out.println("使用时间:"+ (System.currentTimeMillis()-start) + " ms");
+
+ // 然后退出main线程
+ }
+
+ private static int sum() {
+ return fibo(36);
+ }
+
+ private static int fibo(int a) {
+ if ( a < 2)
+ return 1;
+ return fibo(a-1) + fibo(a-2);
+ }
+
+ public static class FiboRunnable implements Runnable{
+ private int result;
+ @Override
+ public void run() {
+ result = sum();
+ }
+
+ public int getResult() {
+ return result;
+ }
+
+ public void setResult(int result) {
+ this.result = result;
+ }
+ }
+}
diff --git a/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method7.java b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method7.java
new file mode 100644
index 00000000..483b7bc8
--- /dev/null
+++ b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method7.java
@@ -0,0 +1,70 @@
+package java0.conc0303.homework.work2;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * 本周作业:(必做)思考有多少种方式,在main函数启动一个新线程或线程池,
+ * 异步运行一个方法,拿到这个方法的返回值后,退出主线程?
+ * 写出你的方法,越多越好,提交到github。
+ *
+ * 一个简单的代码参考:
+ */
+public class Method7 {
+
+ public static void main(String[] args) {
+
+ long start=System.currentTimeMillis();
+
+ // 在这里创建一个线程或线程池,
+ // 异步执行 下面方法
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ FiboRunnable fiboRunnable = new FiboRunnable(countDownLatch);
+ Thread thread = new Thread(fiboRunnable);
+ thread.start();
+
+ try {
+ countDownLatch.await();
+ System.out.println(fiboRunnable.getResult());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+
+ System.out.println("使用时间:"+ (System.currentTimeMillis()-start) + " ms");
+
+ // 然后退出main线程
+ }
+
+ private static int sum() {
+ return fibo(36);
+ }
+
+ private static int fibo(int a) {
+ if ( a < 2)
+ return 1;
+ return fibo(a-1) + fibo(a-2);
+ }
+
+ public static class FiboRunnable implements Runnable{
+ private int result;
+ private CountDownLatch countDownLatch;
+
+ public FiboRunnable(CountDownLatch countDownLatch) {
+ this.countDownLatch = countDownLatch;
+ }
+
+ @Override
+ public void run() {
+ result = sum();
+ countDownLatch.countDown();
+ }
+
+ public int getResult() {
+ return result;
+ }
+
+ public void setResult(int result) {
+ this.result = result;
+ }
+ }
+}
diff --git a/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method8.java b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method8.java
new file mode 100644
index 00000000..ce7c0493
--- /dev/null
+++ b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method8.java
@@ -0,0 +1,80 @@
+package java0.conc0303.homework.work2;
+
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+
+/**
+ * 本周作业:(必做)思考有多少种方式,在main函数启动一个新线程或线程池,
+ * 异步运行一个方法,拿到这个方法的返回值后,退出主线程?
+ * 写出你的方法,越多越好,提交到github。
+ *
+ * 一个简单的代码参考:
+ */
+public class Method8 {
+
+ public static void main(String[] args) {
+
+ long start=System.currentTimeMillis();
+
+ // 在这里创建一个线程或线程池,
+ // 异步执行 下面方法
+ CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
+ FiboRunnable fiboRunnable = new FiboRunnable(cyclicBarrier);
+ Thread thread = new Thread(fiboRunnable);
+ thread.start();
+
+ try {
+ cyclicBarrier.await();
+ System.out.println(fiboRunnable.getResult());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (BrokenBarrierException e) {
+ e.printStackTrace();
+ }
+
+
+ System.out.println("使用时间:"+ (System.currentTimeMillis()-start) + " ms");
+
+ // 然后退出main线程
+ }
+
+ private static int sum() {
+ return fibo(36);
+ }
+
+ private static int fibo(int a) {
+ if ( a < 2)
+ return 1;
+ return fibo(a-1) + fibo(a-2);
+ }
+
+ public static class FiboRunnable implements Runnable{
+ private int result;
+ private CyclicBarrier cyclicBarrier;
+
+ public FiboRunnable(CyclicBarrier cyclicBarrier) {
+ this.cyclicBarrier = cyclicBarrier;
+ }
+
+ @Override
+ public void run() {
+ result = sum();
+ try {
+ cyclicBarrier.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (BrokenBarrierException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public int getResult() {
+ return result;
+ }
+
+ public void setResult(int result) {
+ this.result = result;
+ }
+ }
+}
diff --git a/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method9.java b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method9.java
new file mode 100644
index 00000000..701762fb
--- /dev/null
+++ b/03concurrency/0301/src/main/java/java0/conc0303/homework/work2/Method9.java
@@ -0,0 +1,70 @@
+package java0.conc0303.homework.work2;
+
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 本周作业:(必做)思考有多少种方式,在main函数启动一个新线程或线程池,
+ * 异步运行一个方法,拿到这个方法的返回值后,退出主线程?
+ * 写出你的方法,越多越好,提交到github。
+ *
+ * 一个简单的代码参考:
+ */
+public class Method9 {
+ final static ReentrantLock lock = new ReentrantLock();
+ final static Condition condition = lock.newCondition();
+ static int result;
+
+ public static void main(String[] args) {
+
+ long start=System.currentTimeMillis();
+
+ // 在这里创建一个线程或线程池,
+ // 异步执行 下面方法
+ Thread thread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ lock.lock();
+ result = sum();
+ condition.signal();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }finally {
+ lock.unlock();
+ }
+
+ }
+ });
+ thread.start();
+
+
+ try {
+ lock.lock();
+ condition.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }finally {
+ lock.unlock();
+ }
+ System.out.println(result);
+
+ System.out.println("使用时间:"+ (System.currentTimeMillis()-start) + " ms");
+
+ // 然后退出main线程
+ }
+
+ private static int sum() {
+ return fibo(36);
+ }
+
+ private static int fibo(int a) {
+ if ( a < 2)
+ return 1;
+ return fibo(a-1) + fibo(a-2);
+ }
+
+
+}
diff --git "a/03concurrency/0301/src/main/java/java0/conc0303/homework/work6/Java\345\244\232\347\272\277\347\250\213.png" "b/03concurrency/0301/src/main/java/java0/conc0303/homework/work6/Java\345\244\232\347\272\277\347\250\213.png"
new file mode 100644
index 00000000..18baf5e8
Binary files /dev/null and "b/03concurrency/0301/src/main/java/java0/conc0303/homework/work6/Java\345\244\232\347\272\277\347\250\213.png" differ
diff --git a/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/HIkariDemo.java b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/HIkariDemo.java
new file mode 100644
index 00000000..c2a6362d
--- /dev/null
+++ b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/HIkariDemo.java
@@ -0,0 +1,76 @@
+package io.nononi.db.dbdemo.jdbc;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Random;
+
+/**
+ * 使用Hikati连接池
+ */
+public class HIkariDemo {
+ private static HikariDataSource dataSource;
+
+ static {
+
+ //初始化HikariConfig配置
+ HikariConfig config = new HikariConfig();
+ config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
+ config.setUsername("root");
+ config.setPassword("root");
+ config.setDriverClassName("com.mysql.jdbc.Driver");
+ config.setMaximumPoolSize(20);
+ config.setMinimumIdle(10);
+ config.setAutoCommit(false);
+ config.setConnectionTimeout(30000);
+ //初始化HikariDataSource
+ dataSource = new HikariDataSource(config);
+ }
+
+ public static Connection getConnection() throws SQLException {
+ return dataSource.getConnection();
+ }
+
+ public static void main(String[] args) throws SQLException {
+ Random random = new Random();
+ Connection conn = null;
+ try {
+ conn = getConnection();
+ conn.setAutoCommit(false);
+ String sql = "INSERT INTO `user` (id, name, pwd) VALUES(?, ?, ?);";
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ long begin = System.currentTimeMillis();
+ for (int i = 0; i < 100000; i++) {
+ preparedStatement.setInt(1, i + 1);
+ preparedStatement.setString(2, "name_" + i);
+ preparedStatement.setInt(3, random.nextInt(9999));
+ preparedStatement.addBatch();
+ if ((i + 1) % 200 == 0) {
+ preparedStatement.executeBatch();
+ preparedStatement.clearBatch();
+ }
+ }
+ if (100000 % 200 != 0) {
+ preparedStatement.executeBatch();
+ preparedStatement.clearBatch();
+ }
+ conn.commit();
+ long end = System.currentTimeMillis();
+ System.out.println("Time: " + (end - begin));
+ preparedStatement.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ try {
+ conn.rollback();
+ } catch (SQLException ex) {
+ ex.printStackTrace();
+ }
+ } finally {
+ conn.close();
+
+ }
+ }
+}
diff --git a/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcBatchDemo.java b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcBatchDemo.java
new file mode 100644
index 00000000..5399761d
--- /dev/null
+++ b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcBatchDemo.java
@@ -0,0 +1,68 @@
+package io.nononi.db.dbdemo.jdbc;
+
+import java.sql.*;
+import java.util.Random;
+
+/**
+ * 批处理模式
+ */
+public class JdbcBatchDemo {
+ public static void main(String[] args) throws Exception {
+ Random random = new Random();
+ Connection conn = null;
+ try {
+ conn = getConn();
+ conn.setAutoCommit(false);
+ String sql = "INSERT INTO `user` (id, name, pwd) VALUES(?, ?, ?);";
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ long begin = System.currentTimeMillis();
+ for (int i = 0; i < 100000; i++) {
+ preparedStatement.setInt(1, i + 1);
+ preparedStatement.setString(2, "name_" + i);
+ preparedStatement.setInt(3, random.nextInt(9999));
+ preparedStatement.addBatch();
+ if ((i + 1) % 200 == 0) {
+ preparedStatement.executeBatch();
+ preparedStatement.clearBatch();
+ }
+ }
+ if (100000 % 200 != 0) {
+ preparedStatement.executeBatch();
+ preparedStatement.clearBatch();
+ }
+ conn.commit();
+ long end = System.currentTimeMillis();
+ System.out.println("Time: " + (end - begin));
+ preparedStatement.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ try {
+ conn.rollback();
+ } catch (SQLException ex) {
+ ex.printStackTrace();
+ }
+ } finally {
+ conn.close();
+
+ }
+
+ }
+
+ private static Connection getConn() {
+ String driver = "com.mysql.jdbc.Driver";
+ String url = "jdbc:mysql://localhost:3306/test";
+ String username = "root";
+ String password = "root";
+ Connection conn = null;
+ try {
+ Class.forName(driver); //classLoader,加载对应驱动
+ conn = (Connection) DriverManager.getConnection(url, username, password);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return conn;
+ }
+
+}
diff --git a/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcDemo.java b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcDemo.java
new file mode 100644
index 00000000..4eaa8b0e
--- /dev/null
+++ b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcDemo.java
@@ -0,0 +1,74 @@
+package io.nononi.db.dbdemo.jdbc;
+
+import java.sql.*;
+
+/**
+ * JDBC增删改查,开启事务
+ */
+public class JdbcDemo {
+ public static void main(String[] args) throws Exception {
+ Connection conn = getConn();
+ System.out.println("开始查询:");
+ select(conn);
+ insert(conn, 20, "Amy", 1234);
+ System.out.println("插入后查询:");
+ select(conn);
+ update(conn, 20, "Bob", 1111);
+ System.out.println("更新后查询:");
+ select(conn);
+ delete(conn, 20);
+ System.out.println("删除后查询:");
+ select(conn);
+ conn.close();
+
+
+ }
+
+ private static Connection getConn() {
+ String driver = "com.mysql.jdbc.Driver";
+ String url = "jdbc:mysql://localhost:3306/test";
+ String username = "root";
+ String password = "root";
+ Connection conn = null;
+ try {
+ Class.forName(driver); //classLoader,加载对应驱动
+ conn = (Connection) DriverManager.getConnection(url, username, password);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return conn;
+ }
+
+ private static void select(Connection connection) throws SQLException {
+ Statement statement = connection.createStatement();
+ ResultSet resultSet = statement.executeQuery("SELECT * FROM user");
+ while (resultSet.next()) {
+ System.out.print(resultSet.getInt("id") + " ");
+ System.out.print(resultSet.getString("name") + " ");
+ System.out.println(resultSet.getInt("pwd") + " ");
+ }
+ System.out.println("");
+ }
+
+ private static boolean insert(Connection connection, int id, String name, int pwd) throws SQLException {
+ Statement statement = connection.createStatement();
+ String sql = "INSERT INTO `user` (id, name, pwd) VALUES(" + id + ",'" + name + "'," + pwd + ");";
+ return statement.execute(sql);
+
+ }
+
+ private static boolean update(Connection connection, int id, String name, int pwd) throws SQLException {
+ Statement statement = connection.createStatement();
+ String sql = "UPDATE `user` SET name ='" + name + "'," + "pwd = " + pwd + " WHERE id =" + pwd + ";";
+ return statement.execute(sql);
+ }
+
+ private static int delete(Connection connection, int pwd) throws SQLException {
+ Statement statement = connection.createStatement();
+ String sql = "DELETE FROM `user` WHERE id=" + pwd + ";";
+ return statement.executeUpdate(sql);
+ }
+
+}
diff --git a/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcPreStmtDemo.java b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcPreStmtDemo.java
new file mode 100644
index 00000000..855f42d8
--- /dev/null
+++ b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcPreStmtDemo.java
@@ -0,0 +1,97 @@
+package io.nononi.db.dbdemo.jdbc;
+
+import java.sql.*;
+
+/**
+ * PrepareStatement 方式改造
+ */
+public class JdbcPreStmtDemo {
+ public static void main(String[] args) throws Exception {
+ Connection conn = null;
+ try {
+ conn = getConn();
+ conn.setAutoCommit(false);
+ System.out.println("开始查询:");
+ select(conn);
+ insert(conn, 20, "Amy", 1234);
+ System.out.println("插入后查询:");
+ select(conn);
+ update(conn, 20, "Bob", 1111);
+ System.out.println("更新后查询:");
+ select(conn);
+ delete(conn, 20);
+ System.out.println("删除后查询:");
+ select(conn);
+ conn.commit();
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ try {
+ conn.rollback();
+ } catch (SQLException ex) {
+ ex.printStackTrace();
+ }
+ } finally {
+ conn.close();
+ }
+
+ }
+
+ private static Connection getConn() {
+ String driver = "com.mysql.jdbc.Driver";
+ String url = "jdbc:mysql://localhost:3306/test";
+ String username = "root";
+ String password = "root";
+ Connection conn = null;
+ try {
+ Class.forName(driver); //classLoader,加载对应驱动
+ conn = (Connection) DriverManager.getConnection(url, username, password);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return conn;
+ }
+
+ private static void select(Connection connection) throws SQLException {
+ String sql = "SELECT * FROM user;";
+ PreparedStatement stmt = connection.prepareStatement(sql);
+ ResultSet resultSet = stmt.executeQuery();
+ while (resultSet.next()) {
+ System.out.print(resultSet.getInt("id") + " ");
+ System.out.print(resultSet.getString("name") + " ");
+ System.out.println(resultSet.getInt("pwd") + " ");
+ }
+ System.out.println("");
+ }
+
+ private static int insert(Connection connection, int id, String name, int pwd) throws SQLException {
+ String sql = "INSERT INTO `user` (id, name, pwd) VALUES(?, ?, ?);";
+ PreparedStatement stmt = connection.prepareStatement(sql);
+ stmt.setInt(1,id);
+ stmt.setString(2,name);
+ stmt.setInt(3,pwd);
+ return stmt.executeUpdate();
+
+ }
+
+ private static int update(Connection connection, int id, String name, int pwd) throws SQLException {
+ String sql = "UPDATE `user` SET name = ?, pwd = ? WHERE id = ?;";
+ PreparedStatement stmt = connection.prepareStatement(sql);
+ stmt.setString(1,name);
+ stmt.setInt(2,pwd);
+ stmt.setInt(3,id);
+ return stmt.executeUpdate();
+ }
+
+ private static int delete(Connection connection, int id) throws SQLException {
+
+
+ String sql = "DELETE FROM `user` WHERE id=?;";
+ PreparedStatement stmt = connection.prepareStatement(sql);
+ stmt.setInt(1,id);
+ return stmt.executeUpdate();
+ }
+
+}
diff --git a/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcTransactionDemo.java b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcTransactionDemo.java
new file mode 100644
index 00000000..f7f65e56
--- /dev/null
+++ b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/JdbcTransactionDemo.java
@@ -0,0 +1,87 @@
+package io.nononi.db.dbdemo.jdbc;
+
+import java.sql.*;
+
+/**
+ * JDBC增删改查,开启事务
+ */
+public class JdbcTransactionDemo {
+ public static void main(String[] args) throws Exception {
+ Connection conn = null;
+ try{
+ conn = getConn();
+ conn.setAutoCommit(false);
+ System.out.println("开始查询:");
+ select(conn);
+ insert(conn,20,"Amy",1234);
+ System.out.println("插入后查询:");
+ select(conn);
+ update(conn,20,"Bob",1111);
+ System.out.println("更新后查询:");
+ select(conn);
+ delete(conn,20);
+ System.out.println("删除后查询:");
+ select(conn);
+ conn.commit();
+
+ }catch (SQLException e){
+ e.printStackTrace();
+ try {
+ conn.rollback();
+ } catch (SQLException ex) {
+ ex.printStackTrace();
+ }
+ }finally {
+ conn.close();
+ }
+
+ }
+
+ private static Connection getConn() {
+ String driver = "com.mysql.jdbc.Driver";
+ String url = "jdbc:mysql://localhost:3306/test";
+ String username = "root";
+ String password = "root";
+ Connection conn = null;
+ try {
+ Class.forName(driver); //classLoader,加载对应驱动
+ conn = (Connection) DriverManager.getConnection(url, username, password);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return conn;
+ }
+
+ private static void select(Connection connection) throws SQLException {
+ Statement statement = connection.createStatement();
+ ResultSet resultSet = statement.executeQuery("SELECT * FROM user");
+ while (resultSet.next()){
+ System.out.print(resultSet.getInt("id")+ " ");
+ System.out.print(resultSet.getString("name")+ " ");
+ System.out.println(resultSet.getInt("pwd")+ " ");
+ }
+ System.out.println("");
+ }
+
+ private static boolean insert(Connection connection,int id, String name, int pwd) throws SQLException {
+ Statement statement = connection.createStatement();
+ String sql = "INSERT INTO `user` (id, name, pwd) VALUES("+ id+ ",'"+ name +"'," +pwd +");";
+ return statement.execute(sql);
+
+ }
+
+ private static boolean update(Connection connection,int id, String name, int pwd) throws SQLException {
+ Statement statement = connection.createStatement();
+ String sql = "UPDATE `user` SET name ='"+name+"'," +"pwd = "+ pwd+" WHERE id =" +pwd + ";";
+ return statement.execute(sql);
+ }
+
+ private static int delete(Connection connection, int pwd) throws SQLException {
+ Statement statement = connection.createStatement();
+ String sql = "DELETE FROM `user` WHERE id=" +pwd + ";";
+ return statement.executeUpdate(sql);
+ }
+
+}
diff --git a/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/User.java b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/User.java
new file mode 100644
index 00000000..f11aca4e
--- /dev/null
+++ b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/jdbc/User.java
@@ -0,0 +1,31 @@
+package io.nononi.db.dbdemo.jdbc;
+
+public class User {
+ private Integer id;
+ private String name;
+ private Integer pwd;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getPwd() {
+ return pwd;
+ }
+
+ public void setPwd(Integer pwd) {
+ this.pwd = pwd;
+ }
+}
diff --git a/04fx/homework10/src/main/java/io/nononi/db/dbdemo/shardingdb/ShardingDbDemo.java b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/shardingdb/ShardingDbDemo.java
new file mode 100644
index 00000000..4e2a0129
--- /dev/null
+++ b/04fx/homework10/src/main/java/io/nononi/db/dbdemo/shardingdb/ShardingDbDemo.java
@@ -0,0 +1,97 @@
+package io.nononi.db.dbdemo.shardingdb;
+
+import java.sql.*;
+import java.util.Random;
+
+/**
+ * sharding_db demo
+ */
+public class ShardingDbDemo {
+ public static void main(String[] args) throws Exception {
+ Connection conn = null;
+ Random random = new Random();
+ try {
+ conn = getConn();
+ conn.setAutoCommit(false);
+ System.out.println("开始查询:");
+ select(conn);
+ insert(conn, random.nextInt(100000), "OK");
+ System.out.println("插入后查询:");
+ select(conn);
+ update(conn, 724643077406830593L, "FAIL");
+ System.out.println("更新后查询:");
+ select(conn);
+ delete(conn, 724643077406830593L);
+ System.out.println("删除后查询:");
+ select(conn);
+ conn.commit();
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ try {
+ conn.rollback();
+ } catch (SQLException ex) {
+ ex.printStackTrace();
+ }
+ } finally {
+ conn.close();
+ }
+
+ }
+
+ private static Connection getConn() {
+ String driver = "com.mysql.jdbc.Driver";
+ String url = "jdbc:mysql://localhost:3307/sharding_db";
+ String username = "root";
+ String password = "root";
+ Connection conn = null;
+ try {
+ Class.forName(driver); //classLoader,加载对应驱动
+ conn = (Connection) DriverManager.getConnection(url, username, password);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return conn;
+ }
+
+ private static void select(Connection connection) throws SQLException {
+ String sql = "SELECT * FROM `t_order`;";
+ PreparedStatement stmt = connection.prepareStatement(sql);
+ ResultSet resultSet = stmt.executeQuery();
+ while (resultSet.next()) {
+ System.out.print(resultSet.getLong("order_id") + " ");
+ System.out.print(resultSet.getInt("user_id") + " ");
+ System.out.println(resultSet.getString("status") + " ");
+ }
+ System.out.println("");
+ }
+
+ private static int insert(Connection connection, int user_id, String status) throws SQLException {
+ String sql = "INSERT INTO `t_order` (user_id, status) VALUES(?, ?);";
+ PreparedStatement stmt = connection.prepareStatement(sql);
+ stmt.setInt(1,user_id);
+ stmt.setString(2,status);
+ return stmt.executeUpdate();
+
+ }
+
+ private static int update(Connection connection, long order_id, String status) throws SQLException {
+ String sql = "UPDATE `t_order` SET status = ? WHERE order_id = ?;";
+ PreparedStatement stmt = connection.prepareStatement(sql);
+ stmt.setString(1,status);
+ stmt.setLong(2,order_id);
+ return stmt.executeUpdate();
+ }
+
+ private static int delete(Connection connection, long order_id) throws SQLException {
+
+
+ String sql = "DELETE FROM `t_order` WHERE order_id=? ;";
+ PreparedStatement stmt = connection.prepareStatement(sql);
+ stmt.setLong(1,order_id);
+ return stmt.executeUpdate();
+ }
+
+}
diff --git a/04fx/homework2/src/main/java/io/nononi/week5/annotation/AnnotationConfig.java b/04fx/homework2/src/main/java/io/nononi/week5/annotation/AnnotationConfig.java
new file mode 100644
index 00000000..cc97de5c
--- /dev/null
+++ b/04fx/homework2/src/main/java/io/nononi/week5/annotation/AnnotationConfig.java
@@ -0,0 +1,12 @@
+package io.nononi.week5.annotation;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 利用注解注入
+ */
+@Configuration
+@ComponentScan
+public class AnnotationConfig {
+}
diff --git a/04fx/homework2/src/main/java/io/nononi/week5/annotation/AnnotationExample.java b/04fx/homework2/src/main/java/io/nononi/week5/annotation/AnnotationExample.java
new file mode 100644
index 00000000..67f52c65
--- /dev/null
+++ b/04fx/homework2/src/main/java/io/nononi/week5/annotation/AnnotationExample.java
@@ -0,0 +1,13 @@
+package io.nononi.week5.annotation;
+
+import org.springframework.stereotype.Component;
+
+/**
+ * 自动注入样例
+ */
+@Component
+public class AnnotationExample {
+ public void printMsg(){
+ System.out.println("通过注解自动注入");
+ }
+}
diff --git a/04fx/homework2/src/main/java/io/nononi/week5/javacode/JavaCodeConfig.java b/04fx/homework2/src/main/java/io/nononi/week5/javacode/JavaCodeConfig.java
new file mode 100644
index 00000000..6c6dd12e
--- /dev/null
+++ b/04fx/homework2/src/main/java/io/nononi/week5/javacode/JavaCodeConfig.java
@@ -0,0 +1,16 @@
+package io.nononi.week5.javacode;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * java配置类
+ */
+@Configuration
+public class JavaCodeConfig {
+
+ @Bean
+ public JavaCodeExample javaCodeExample(){
+ return new JavaCodeExample();
+ }
+}
diff --git a/04fx/homework2/src/main/java/io/nononi/week5/javacode/JavaCodeExample.java b/04fx/homework2/src/main/java/io/nononi/week5/javacode/JavaCodeExample.java
new file mode 100644
index 00000000..7a062df6
--- /dev/null
+++ b/04fx/homework2/src/main/java/io/nononi/week5/javacode/JavaCodeExample.java
@@ -0,0 +1,13 @@
+package io.nononi.week5.javacode;
+
+import org.springframework.stereotype.Component;
+
+/**
+ * 待装配的Bean
+ */
+@Component
+public class JavaCodeExample {
+ public void printMsg(){
+ System.out.println("Java配置类注入");
+ }
+}
diff --git a/04fx/homework2/src/main/java/io/nononi/week5/xml/XmlExample.java b/04fx/homework2/src/main/java/io/nononi/week5/xml/XmlExample.java
new file mode 100644
index 00000000..52168204
--- /dev/null
+++ b/04fx/homework2/src/main/java/io/nononi/week5/xml/XmlExample.java
@@ -0,0 +1,7 @@
+package io.nononi.week5.xml;
+
+public class XmlExample {
+ public void printMsg(){
+ System.out.println("XML装配Bean");
+ }
+}
diff --git a/04fx/homework2/src/main/resources/xmlConfig.xml b/04fx/homework2/src/main/resources/xmlConfig.xml
new file mode 100644
index 00000000..d851eaf3
--- /dev/null
+++ b/04fx/homework2/src/main/resources/xmlConfig.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/04fx/homework8/src/main/java/io/nononi/starter/Klass.java b/04fx/homework8/src/main/java/io/nononi/starter/Klass.java
new file mode 100644
index 00000000..74b7c844
--- /dev/null
+++ b/04fx/homework8/src/main/java/io/nononi/starter/Klass.java
@@ -0,0 +1,42 @@
+package io.nononi.starter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Klass {
+ private int id;
+ List students;
+
+ public Klass(int id) {
+ this.id = id;
+ this.students = new ArrayList<>();
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public List getStudents() {
+ return students;
+ }
+
+ public void setStudents(List students) {
+ this.students = students;
+ }
+
+ public void addStudent(Student student) {
+ students.add(student);
+ }
+
+ @Override
+ public String toString() {
+ return "Klass{" +
+ "id=" + id +
+ ", students=" + students +
+ '}';
+ }
+}
diff --git a/04fx/homework8/src/main/java/io/nononi/starter/School.java b/04fx/homework8/src/main/java/io/nononi/starter/School.java
new file mode 100644
index 00000000..dc928853
--- /dev/null
+++ b/04fx/homework8/src/main/java/io/nononi/starter/School.java
@@ -0,0 +1,27 @@
+package io.nononi.starter;
+
+import java.util.List;
+
+public class School {
+ private List klasses;
+
+ public School(List klasses) {
+ this.klasses = klasses;
+ }
+
+
+ public List getKlasses() {
+ return klasses;
+ }
+
+ public void setKlasses(List klasses) {
+ this.klasses = klasses;
+ }
+
+ @Override
+ public String toString() {
+ return "School{" +
+ "klasses=" + klasses +
+ '}';
+ }
+}
diff --git a/04fx/homework8/src/main/java/io/nononi/starter/SchoolAutoConfiguration.java b/04fx/homework8/src/main/java/io/nononi/starter/SchoolAutoConfiguration.java
new file mode 100644
index 00000000..906e0c7c
--- /dev/null
+++ b/04fx/homework8/src/main/java/io/nononi/starter/SchoolAutoConfiguration.java
@@ -0,0 +1,51 @@
+package io.nononi.starter;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Configuration
+@EnableConfigurationProperties(SchoolProperties.class)
+@ConditionalOnProperty(prefix = "school", value = "enabled", havingValue = "true")
+@PropertySource("classpath:application.properties")
+public class SchoolAutoConfiguration {
+
+ @Autowired
+ private SchoolProperties schoolProperties;
+
+ @Bean
+ public School school() {
+ List studentIds = schoolProperties.getStudentIds();
+ List studentNames = schoolProperties.getStudentNames();
+ List klassIds = schoolProperties.getKlassIds();
+ List