inputPath, String outputPath) {
39 | }
40 | public boolean isCancelled() {
41 | return false;
42 | }
43 | });
44 |
45 | if (!res.getFailures().isEmpty()) {
46 | StringBuilder sb = new StringBuilder();
47 | sb.append("Failed decompilation of " + res.getFailures().size() + " classes: ");
48 | Iterator failureIterator = res.getFailures().iterator();
49 | while (failureIterator.hasNext()) {
50 | DecompilationFailure dex = (DecompilationFailure)failureIterator.next();
51 | sb.append(System.lineSeparator() + " ").append(dex.getMessage());
52 | }
53 | System.out.println(sb.toString());
54 | }
55 | System.out.println("Compilation results: " + res.getDecompiledFiles().size() + " succeeded, " + res.getFailures().size() + " failed.");
56 | dec.close();
57 | Long end = System.currentTimeMillis();
58 | return end - start;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/java-lab/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | lab-notes
7 | com.wdbyte
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | java-lab
13 |
14 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/classloader/BaseManager.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.classloader;
2 |
3 | /**
4 | *
5 | * 实现这个接口的子类,需要动态更新。也就是热加载
6 | *
7 | * @Author niujinpeng
8 | * @Date 2019/10/24 23:29
9 | */
10 | public interface BaseManager {
11 |
12 | public void logic();
13 | }
14 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/classloader/ClassLoadTest.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.classloader;
2 |
3 | /**
4 | *
5 | *
6 | * 测试 Java 类的热加载
7 | *
8 | * @Author niujinpeng
9 | * @Date 2019/10/24 23:55
10 | */
11 | public class ClassLoadTest {
12 |
13 | public static void main(String[] args) {
14 | new Thread(new MsgHandle()).start();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/classloader/LoadInfo.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.classloader;
2 |
3 | /**
4 | *
5 | * 封装加载类的信息
6 | *
7 | * @Author niujinpeng
8 | * @Date 2019/10/24 23:32
9 | */
10 | public class LoadInfo {
11 |
12 | /** 自定义的类加载器 */
13 | private MyClasslLoader myClasslLoader;
14 |
15 | /** 记录要加载的类的时间戳-->加载的时间 */
16 | private long loadTime;
17 |
18 | /** 需要被热加载的类 */
19 | private BaseManager manager;
20 |
21 | public LoadInfo(MyClasslLoader myClasslLoader, long loadTime) {
22 | this.myClasslLoader = myClasslLoader;
23 | this.loadTime = loadTime;
24 | }
25 |
26 | public MyClasslLoader getMyClasslLoader() {
27 | return myClasslLoader;
28 | }
29 |
30 | public void setMyClasslLoader(MyClasslLoader myClasslLoader) {
31 | this.myClasslLoader = myClasslLoader;
32 | }
33 |
34 | public long getLoadTime() {
35 | return loadTime;
36 | }
37 |
38 | public void setLoadTime(long loadTime) {
39 | this.loadTime = loadTime;
40 | }
41 |
42 | public BaseManager getManager() {
43 | return manager;
44 | }
45 |
46 | public void setManager(BaseManager manager) {
47 | this.manager = manager;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/classloader/ManagerFactory.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.classloader;
2 |
3 | import java.io.File;
4 | import java.lang.reflect.InvocationTargetException;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | /**
9 | *
10 | * 加载 manager 的工厂
11 | *
12 | * @Author niujinpeng
13 | * @Date 2019/10/24 23:38
14 | */
15 | public class ManagerFactory {
16 |
17 | /** 记录热加载类的加载信息 */
18 | private static final Map loadTimeMap = new HashMap<>();
19 |
20 | /** 要加载的类的 classpath */
21 | public static final String CLASS_PATH = "D:\\IdeaProjectMy\\lab-notes\\target\\classes\\";
22 |
23 | /** 实现热加载的类的全名称(包名+类名 ) */
24 | public static final String MY_MANAGER = "net.codingme.box.classloader.MyManager";
25 |
26 | public static BaseManager getManager(String className) {
27 | File loadFile = new File(CLASS_PATH + className.replaceAll("\\.", "/") + ".class");
28 | // 获取最后一次修改时间
29 | long lastModified = loadFile.lastModified();
30 | System.out.println("当前的类时间:" + lastModified);
31 | // loadTimeMap 不包含 ClassName 为 key 的信息,证明这个类没有被加载,要加载到 JVM
32 | if (loadTimeMap.get(className) == null) {
33 | load(className, lastModified);
34 | } // 加载类的时间戳变化了,我们同样要重新加载这个类到 JVM。
35 | else if (loadTimeMap.get(className).getLoadTime() != lastModified) {
36 | load(className, lastModified);
37 | }
38 | return loadTimeMap.get(className).getManager();
39 | }
40 |
41 | /**
42 | * 加载 class ,缓存到 loadTimeMap
43 | *
44 | * @param className
45 | * @param lastModified
46 | */
47 | private static void load(String className, long lastModified) {
48 | MyClasslLoader myClasslLoader = new MyClasslLoader(className);
49 | Class loadClass = null;
50 | // 加载
51 | try {
52 | loadClass = myClasslLoader.loadClass(className);
53 | } catch (ClassNotFoundException e) {
54 | e.printStackTrace();
55 | }
56 |
57 | BaseManager manager = newInstance(loadClass);
58 | LoadInfo loadInfo = new LoadInfo(myClasslLoader, lastModified);
59 | loadInfo.setManager(manager);
60 | loadTimeMap.put(className, loadInfo);
61 | }
62 |
63 | /**
64 | * 以反射的方式创建 BaseManager 的子类对象
65 | *
66 | * @param loadClass
67 | * @return
68 | */
69 | private static BaseManager newInstance(Class loadClass) {
70 | try {
71 | return (BaseManager)loadClass.getConstructor(new Class[] {}).newInstance(new Object[] {});
72 | } catch (InstantiationException e) {
73 | e.printStackTrace();
74 | } catch (IllegalAccessException e) {
75 | e.printStackTrace();
76 | } catch (InvocationTargetException e) {
77 | e.printStackTrace();
78 | } catch (NoSuchMethodException e) {
79 | e.printStackTrace();
80 | }
81 | return null;
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/classloader/MsgHandle.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.classloader;
2 |
3 | /**
4 | *
5 | *
6 | * 后台启动一条线程,不断检测是否要刷新重新加载,实现了热加载的类
7 | *
8 | * @Author niujinpeng
9 | * @Date 2019/10/24 23:53
10 | */
11 | public class MsgHandle implements Runnable {
12 | @Override
13 | public void run() {
14 | while (true) {
15 | BaseManager manager = ManagerFactory.getManager(ManagerFactory.MY_MANAGER);
16 | manager.logic();
17 | try {
18 | Thread.sleep(2000);
19 | } catch (InterruptedException e) {
20 | e.printStackTrace();
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/classloader/MyClasslLoader.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.classloader;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 |
7 | /**
8 | *
9 | * 自定义 Java类加载器来实现Java 类的热加载
10 | *
11 | * @Author niujinpeng
12 | * @Date 2019/10/24 23:22
13 | */
14 | public class MyClasslLoader extends ClassLoader {
15 |
16 | /** 要加载的 Java 类的 classpath 路径 */
17 | private String classpath;
18 |
19 | public MyClasslLoader(String classpath) {
20 | // 指定父加载器
21 | super(ClassLoader.getSystemClassLoader());
22 | this.classpath = classpath;
23 | }
24 |
25 | @Override
26 | protected Class> findClass(String name) throws ClassNotFoundException {
27 | byte[] data = this.loadClassData(name);
28 | return this.defineClass(name, data, 0, data.length);
29 | }
30 |
31 | /**
32 | * 加载 class 文件中的内容
33 | *
34 | * @param name
35 | * @return
36 | */
37 | private byte[] loadClassData(String name) {
38 | try {
39 | // 传进来是带包名的
40 | name = name.replace(".", "//");
41 | FileInputStream inputStream = new FileInputStream(new File(classpath + name + ".class"));
42 | // 定义字节数组输出流
43 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
44 | int b = 0;
45 | while ((b = inputStream.read()) != -1) {
46 | baos.write(b);
47 | }
48 | inputStream.close();
49 | return baos.toByteArray();
50 | } catch (Exception e) {
51 | e.printStackTrace();
52 | }
53 | return null;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/classloader/MyManager.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.classloader;
2 |
3 | import java.time.LocalTime;
4 |
5 | /**
6 | *
7 | * BaseManager 这个接口的子类要实现类的热加载功能。
8 | *
9 | * @Author niujinpeng
10 | * @Date 2019/10/24 23:30
11 | */
12 | public class MyManager implements BaseManager {
13 |
14 | @Override
15 | public void logic() {
16 | System.out.println(LocalTime.now() + ": Java类的热加载 Oh~~~~ ");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/aio/AioSocketServer.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.aio;
2 |
3 | import java.io.IOException;
4 | import java.io.UnsupportedEncodingException;
5 | import java.net.InetSocketAddress;
6 | import java.nio.ByteBuffer;
7 | import java.nio.channels.AsynchronousServerSocketChannel;
8 | import java.nio.channels.AsynchronousSocketChannel;
9 | import java.nio.channels.CompletionHandler;
10 |
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | /**
15 | * AIO异步通信
16 | *
17 | * Java 异步IO
18 | * 在java的N-IO框架中,需要使用一个重要的selector负责代替应用查询已注册的通道,用于IO事件轮训,
19 | * 管理通道集合等。
20 | *
21 | * A-IO中不是“轮训”方式,而是订阅-通知的方式,所以不需要`selector`了,channel通道可以直接注册
22 | * 监听到操作系统。
23 | *
24 | * @Author niujinpeng
25 | * @Date 2018/10/28 15:58
26 | */
27 | public class AioSocketServer {
28 |
29 |
30 | private static Object waitObject = new Object();
31 |
32 | public static void main(String[] args) throws IOException, InterruptedException {
33 | AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open();
34 |
35 | // 监听IP的83端口
36 | serverSocket.bind(new InetSocketAddress("0.0.0.0", 83));
37 | // 注册监听
38 | serverSocket.accept(null, new ServerSocketChannelHandle(serverSocket));
39 |
40 | synchronized (waitObject) {
41 | waitObject.wait();
42 | }
43 | }
44 | }
45 |
46 | /**
47 | * 用于响应ServerSocketChannel事件
48 | */
49 | class ServerSocketChannelHandle implements CompletionHandler {
50 |
51 | private static final Logger logger = LoggerFactory.getLogger(ServerSocketChannelHandle.class);
52 |
53 | private AsynchronousServerSocketChannel serverSocketChannel;
54 |
55 | ServerSocketChannelHandle(AsynchronousServerSocketChannel serverSocketChannel) {
56 | this.serverSocketChannel = serverSocketChannel;
57 | }
58 |
59 |
60 | @Override
61 | public void completed(AsynchronousSocketChannel socketChannel, Void attachment) {
62 | logger.info("completed(AsynchronousSocketChannel,Void)");
63 | // 注册监听
64 | this.serverSocketChannel.accept(attachment, this);
65 |
66 | // 注册Read事件
67 | ByteBuffer readBuffer = ByteBuffer.allocate(50);
68 | socketChannel.read(readBuffer, new StringBuffer(), new SocketChannelReadHandle(socketChannel, readBuffer));
69 | }
70 |
71 | @Override
72 | public void failed(Throwable exc, Void attachment) {
73 | logger.info("failed(Throwable exc, Void attachment)");
74 | }
75 | }
76 |
77 | /**
78 | * 负责对每一个SocketChannel的数据获取事件进行监听
79 | */
80 | class SocketChannelReadHandle implements CompletionHandler {
81 |
82 | private static final Logger logger = LoggerFactory.getLogger(SocketChannelReadHandle.class);
83 |
84 | private AsynchronousSocketChannel socketChannel;
85 |
86 | private ByteBuffer byteBuffer;
87 |
88 | SocketChannelReadHandle(AsynchronousSocketChannel socketChannel, ByteBuffer byteBuffer) {
89 | this.socketChannel = socketChannel;
90 | this.byteBuffer = byteBuffer;
91 |
92 | }
93 |
94 | @Override
95 | public void completed(Integer result, StringBuffer historyContext) {
96 | // 如果条件成立,说明客户端主动终止了TCP套接字
97 | if (result == -1) {
98 | try {
99 | this.socketChannel.close();
100 | } catch (IOException e) {
101 | logger.error(e.toString());
102 | }
103 | return;
104 | }
105 |
106 | logger.info("completed(Integer result, StringBuffer historyContext)");
107 | this.byteBuffer.flip();
108 | // 如果接收用的byte长度不够,AIO会自动处理成多次通知
109 | byte[] contexts = new byte[1024];
110 | this.byteBuffer.get(contexts, 0, result);
111 | this.byteBuffer.clear();
112 | try {
113 | String nowContent = new String(contexts, 0, result, "UTF-8");
114 | historyContext.append(nowContent);
115 | logger.info("现在接受到的数据:" + historyContext);
116 | } catch (UnsupportedEncodingException e) {
117 | logger.error(e.toString());
118 | }
119 |
120 | // 是否有结束标记
121 | if (historyContext.indexOf("over") == -1) {
122 | return;
123 | }
124 |
125 | // 收到"over“开始处理数据
126 | logger.info("开始处理数据...");
127 | // 清空
128 | historyContext = new StringBuffer();
129 |
130 | // 继续监听
131 | this.socketChannel.read(this.byteBuffer, historyContext, this);
132 |
133 |
134 | }
135 |
136 | @Override
137 | public void failed(Throwable exc, StringBuffer attachment) {
138 | logger.info("客户端异常关闭,服务端关闭TCP通道");
139 | try {
140 | this.socketChannel.close();
141 | } catch (IOException e) {
142 | logger.info(e.toString());
143 | }
144 | }
145 | }
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/aio/SocketClient.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.aio;
2 |
3 | import java.util.concurrent.CountDownLatch;
4 |
5 | /**
6 | *
7 | * BIO客户端
8 | * 模拟20个客户端并发请求,服务端则使用单线程。
9 | *
10 | * @Author niujinpeng
11 | * @Date 2018/10/15 10:50
12 | */
13 | public class SocketClient {
14 | public static void main(String[] args) throws InterruptedException {
15 | // 客户端数量
16 | Integer clientNumber = 1;
17 | CountDownLatch countDownLatch = new CountDownLatch(clientNumber);
18 |
19 | // 分别启动20个客户端
20 | for (int index = 0; index < clientNumber; index++, countDownLatch.countDown()) {
21 | SocketClientRequestThread client = new SocketClientRequestThread(countDownLatch, index);
22 | new Thread(client).start();
23 | }
24 |
25 | synchronized (SocketClient.class) {
26 | SocketClient.class.wait();
27 | }
28 | }
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/aio/SocketClientRequestThread.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.aio;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.net.Socket;
7 | import java.util.concurrent.CountDownLatch;
8 |
9 | /**
10 | *
11 | * 网络客户端,用于模拟请求
12 | *
13 | * @Author niujinpeng
14 | * @Date 2018/10/15 10:53
15 | */
16 | class SocketClientRequestThread implements Runnable {
17 |
18 | private CountDownLatch countDownLatch;
19 |
20 | /**
21 | * 线程的编号
22 | */
23 | private Integer clientIndex;
24 |
25 |
26 | public SocketClientRequestThread(CountDownLatch countDownLatch, Integer clientIndex) {
27 | this.countDownLatch = countDownLatch;
28 | this.clientIndex = clientIndex;
29 | }
30 |
31 | @Override
32 | public void run() {
33 | Socket socket = null;
34 | OutputStream clientRequest = null;
35 | InputStream clientResponse = null;
36 | try {
37 | socket = new Socket("localhost", 83);
38 | clientRequest = socket.getOutputStream();
39 | clientResponse = socket.getInputStream();
40 |
41 | //等待,直到SocketClientDaemon完成所有线程的启动,然后所有线程一起发送请求
42 | this.countDownLatch.await();
43 |
44 | // 发送请求信息
45 | clientRequest.write(("这是第" + this.clientIndex + "个客户端的请求").getBytes());
46 | clientRequest.flush();
47 |
48 | clientRequest.write("over".getBytes());
49 | clientRequest.flush();
50 |
51 | // 等待服务器返回消息
52 | System.out.println("第" + this.clientIndex + "个客户端请求发送完成,等待服务器响应");
53 | //int maxLen = 1024;
54 | //byte[] contentBytes = new byte[maxLen];
55 | //int realLen;
56 | //String message = "";
57 | //
58 | //// 等待服务端返回,in和out不能cloese
59 | //while ((realLen = clientResponse.read(contentBytes, 0, maxLen)) != -1) {
60 | // message += new String(contentBytes, 0, realLen);
61 | //}
62 | //System.out.println("第" + this.clientIndex + "个客户端接受到来自服务器的消息:" + message);
63 |
64 | } catch (IOException e) {
65 | e.printStackTrace();
66 | } catch (InterruptedException e) {
67 | e.printStackTrace();
68 | } finally {
69 | try {
70 | if (clientRequest != null) {
71 | clientRequest.close();
72 | }
73 | if (clientRequest != null) {
74 | clientResponse.close();
75 | }
76 | } catch (IOException e) {
77 | e.printStackTrace();
78 | }
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/bio/SocketClient.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.bio;
2 |
3 | import java.util.concurrent.CountDownLatch;
4 |
5 | /**
6 | *
7 | * BIO客户端
8 | * 模拟20个客户端并发请求,服务端则使用单线程。
9 | *
10 | * @Author niujinpeng
11 | * @Date 2018/10/15 10:50
12 | */
13 | public class SocketClient {
14 | public static void main(String[] args) throws InterruptedException {
15 | // 客户端数量
16 | Integer clientNumber = 20;
17 | CountDownLatch countDownLatch = new CountDownLatch(clientNumber);
18 |
19 | // 分别启动20个客户端
20 | for (int index = 0; index < clientNumber; index++, countDownLatch.countDown()) {
21 | SocketClientRequestThread client = new SocketClientRequestThread(countDownLatch, index);
22 | new Thread(client).start();
23 | }
24 |
25 | synchronized (SocketClient.class) {
26 | SocketClient.class.wait();
27 | }
28 | }
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/bio/SocketClientRequestThread.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.bio;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.net.Socket;
7 | import java.util.concurrent.CountDownLatch;
8 |
9 | /**
10 | *
11 | * 网络客户端,用于模拟请求
12 | *
13 | * @Author niujinpeng
14 | * @Date 2018/10/15 10:53
15 | */
16 | class SocketClientRequestThread implements Runnable {
17 |
18 | private CountDownLatch countDownLatch;
19 |
20 | /**
21 | * 线程的编号
22 | */
23 | private Integer clientIndex;
24 |
25 |
26 | public SocketClientRequestThread(CountDownLatch countDownLatch, Integer clientIndex) {
27 | this.countDownLatch = countDownLatch;
28 | this.clientIndex = clientIndex;
29 | }
30 |
31 | @Override
32 | public void run() {
33 | Socket socket = null;
34 | OutputStream clientRequest = null;
35 | InputStream clientResponse = null;
36 | try {
37 | socket = new Socket("localhost", 83);
38 | clientRequest = socket.getOutputStream();
39 | clientResponse = socket.getInputStream();
40 |
41 | //等待,直到SocketClientDaemon完成所有线程的启动,然后所有线程一起发送请求
42 | this.countDownLatch.await();
43 |
44 | // 发送请求信息
45 | clientRequest.write(("这是第" + this.clientIndex + "个客户端的请求").getBytes());
46 | clientRequest.flush();
47 |
48 | // 等待服务器返回消息
49 | System.out.println("第" + this.clientIndex + "个客户端请求发送完成,等待服务器响应");
50 | int maxLen = 1024;
51 | byte[] contentBytes = new byte[maxLen];
52 | int realLen;
53 | String message = "";
54 |
55 | // 等待服务端返回,in和out不能cloese
56 | while ((realLen = clientResponse.read(contentBytes, 0, maxLen)) != -1) {
57 | message += new String(contentBytes, 0, realLen);
58 | }
59 | System.out.println("第" + this.clientIndex + "个客户端接受到来自服务器的消息:" + message);
60 |
61 | } catch (IOException e) {
62 | e.printStackTrace();
63 | } catch (InterruptedException e) {
64 | e.printStackTrace();
65 | } finally {
66 | try {
67 | if (clientRequest != null) {
68 | clientRequest.close();
69 | }
70 | if (clientRequest != null) {
71 | clientResponse.close();
72 | }
73 | } catch (IOException e) {
74 | e.printStackTrace();
75 | }
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/bio/SocketServer.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.bio;
2 |
3 |
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 | import java.net.ServerSocket;
8 | import java.net.Socket;
9 |
10 | /**
11 | * BIO服务端
12 | *
13 | * 单线程阻塞的服务器端
14 | *
15 | * @Author niujinpeng
16 | * @Date 2018/10/15 11:17
17 | */
18 | public class SocketServer {
19 |
20 | public static void main(String[] args) throws IOException {
21 | ServerSocket serverSocket = new ServerSocket(83);
22 | try {
23 | while (true) {
24 | // 阻塞,直到有数据准备完毕
25 | Socket socket = serverSocket.accept();
26 |
27 | // 开始收取信息
28 | InputStream input = socket.getInputStream();
29 | OutputStream output = socket.getOutputStream();
30 | Integer sourcePort = socket.getPort();
31 | int maxLen = 1024 * 2;
32 | byte[] contextBytes = new byte[maxLen];
33 |
34 | // 阻塞,直到有数据准备完毕
35 | int realLen = input.read(contextBytes, 0, maxLen);
36 | // 读取信息
37 | String message = new String(contextBytes, 0, realLen);
38 |
39 | // 输出接收信息
40 | System.out.println("服务器收到来自端口【" + sourcePort + "】的信息:" + message);
41 | // 响应信息
42 | output.write("Done!".getBytes());
43 |
44 | // 关闭
45 | output.close();
46 | input.close();
47 | socket.close();
48 |
49 | }
50 | } catch (Exception e) {
51 | e.printStackTrace();
52 | } finally {
53 | if (serverSocket != null) {
54 | serverSocket.close();
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/bio/SocketServerThread.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.bio;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.net.ServerSocket;
7 | import java.net.Socket;
8 |
9 | import lombok.extern.slf4j.Slf4j;
10 |
11 | /**
12 | * BIO服务端
13 | *
14 | * 多线程的阻塞的服务端
15 | *
16 | * 当然,接收到客户端的socket后,业务的处理过程可以交给一个线程来做。
17 | * 但还是改变不了socket被一个一个的做accept()的情况。
18 | *
19 | * @Author niujinpeng
20 | * @Date 2018/10/15 11:17
21 | */
22 | @Slf4j
23 | public class SocketServerThread implements Runnable {
24 |
25 | private Socket socket;
26 |
27 | public SocketServerThread(Socket socket) {
28 | this.socket = socket;
29 |
30 | }
31 |
32 | public static void main(String[] args) throws Exception {
33 | ServerSocket serverSocket = new ServerSocket(83);
34 | try {
35 | while (true) {
36 | Socket socket = serverSocket.accept();
37 | //当然业务处理过程可以交给一个线程(这里可以使用线程池),并且线程的创建是很耗资源的。
38 | //最终改变不了.accept()只能一个一个接受socket的情况,并且被阻塞的情况
39 | SocketServerThread socketServerThread = new SocketServerThread(socket);
40 | new Thread(socketServerThread).start();
41 | }
42 | } catch (Exception e) {
43 | System.out.println(e.getMessage());
44 | } finally {
45 | if (serverSocket != null) {
46 | serverSocket.close();
47 | }
48 | }
49 | }
50 |
51 |
52 | @Override
53 | public void run() {
54 | InputStream in = null;
55 | OutputStream out = null;
56 | try {
57 | //下面我们收取信息
58 | in = socket.getInputStream();
59 | out = socket.getOutputStream();
60 | Integer sourcePort = socket.getPort();
61 | int maxLen = 1024;
62 | byte[] contextBytes = new byte[maxLen];
63 | //使用线程,同样无法解决read方法的阻塞问题,
64 | //也就是说read方法处同样会被阻塞,直到操作系统有数据准备好
65 | int realLen = in.read(contextBytes, 0, maxLen);
66 | //读取信息
67 | String message = new String(contextBytes, 0, realLen);
68 |
69 | //下面打印信息
70 | log.info("服务器收到来自于端口:" + sourcePort + "的信息:" + message);
71 |
72 | //下面开始发送信息
73 | out.write("回发响应信息!".getBytes());
74 | } catch (Exception e) {
75 | log.error(e.getMessage(), e);
76 | } finally {
77 | //试图关闭
78 | try {
79 | if (in != null) {
80 | in.close();
81 | }
82 | if (out != null) {
83 | out.close();
84 | }
85 | if (this.socket != null) {
86 | this.socket.close();
87 | }
88 | } catch (IOException e) {
89 | log.error(e.getMessage(), e);
90 | }
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/jdknio/NioBuffer.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.jdknio;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.nio.ByteBuffer;
5 |
6 | /**
7 | * NIO-Buffer
8 | *
9 | * Buffer本质是可以写入可以读取的内存,这块内存被包装成了NIO的Buffer对象,
10 | * 然后为它提供一组用于访问的方法。Java则为java.nio.Buffer实现了基本数据
11 | * 类型的Buffer
12 | *
13 | * @Author niujinpeng
14 | * @Date 2018/10/24 18:28
15 | */
16 | public class NioBuffer {
17 |
18 | public static void main(String[] args) throws UnsupportedEncodingException {
19 | // 申请一个大小为1024bytes的缓冲buffer
20 | ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
21 | System.out.println("申请到的Buffer:" + byteBuffer);
22 |
23 | // 写入helloworld到buffer
24 | byteBuffer.put("HelloWorld".getBytes());
25 | System.out.println("写入HelloWorld到Buffer:" + byteBuffer);
26 |
27 | // 切换为读模式
28 | byteBuffer.flip();
29 | // 当前Buffer已存放的大小
30 | int length = byteBuffer.remaining();
31 | byte[] bytes = new byte[length];
32 |
33 | // 读取bytes长度的数据
34 | byteBuffer.get(bytes);
35 | System.out.println("从buffer读取到数据:" + new String(bytes, "UTF-8"));
36 |
37 | // 切换为compact 清空已读取的数据
38 | byteBuffer.compact();
39 | System.out.println("读取后的Buffer:" + byteBuffer);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/jdknio/NioChannel.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.jdknio;
2 |
3 | import java.io.FileInputStream;
4 | import java.io.IOException;
5 | import java.nio.ByteBuffer;
6 | import java.nio.channels.FileChannel;
7 |
8 | /**
9 | * NIO-Channel
10 | *
11 | * 通道Channel和流类似,不同的是通道的工作模式可以是全双工。
12 | * 也就是说既可以读取,也可以写入。同时也可以异步的进行读写。
13 | * `Channel`连接着底层数据与缓冲区`Buffer`。
14 | *
15 | * @Author niujinpeng
16 | * @Date 2018/10/25 16:27
17 | */
18 | public class NioChannel {
19 |
20 | public static void main(String[] args) throws IOException {
21 | // 申请一个大小为1024bytes的缓冲buffer
22 | ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
23 |
24 | // 初始化Channel数据
25 | FileInputStream fis = new FileInputStream("f:/test.txt");
26 | FileChannel channel = fis.getChannel();
27 | System.out.println("Init Channel size:" + channel.size());
28 |
29 | // 从channel中读取数据
30 | int read = channel.read(byteBuffer);
31 | System.out.println("Read Size :" + read);
32 | System.out.println("byteBuffer:"+byteBuffer);
33 |
34 | // 切换到读取模式
35 | byteBuffer.flip();
36 |
37 | // 输出byteBuffer内容
38 | System.out.print("print byteBuffer:");
39 | while (byteBuffer.hasRemaining()){
40 | System.out.print((char) byteBuffer.get());
41 | }
42 |
43 | byteBuffer.clear();
44 | System.out.println(byteBuffer);
45 | fis.close();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/jdknio/NioSelector.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.jdknio;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.net.ServerSocket;
6 | import java.nio.ByteBuffer;
7 | import java.nio.channels.SelectableChannel;
8 | import java.nio.channels.SelectionKey;
9 | import java.nio.channels.Selector;
10 | import java.nio.channels.ServerSocketChannel;
11 | import java.nio.channels.SocketChannel;
12 | import java.util.Iterator;
13 | import java.util.Set;
14 |
15 | /**
16 | *
17 | * NIO-Selector
18 | * 选择器的使用测试
19 | * Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读
20 | * 写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接
21 | * 。我们也可以称Selector为轮询代理器,事件订阅器或者channel容器管理器。
22 | * 应用程序将向Selector对象注册需要它关注的Channel,以及具体的某一个Channel会对哪些
23 | * IO事件感兴趣。Selector中也会维护一个“已经注册的Channel”的容器。
24 | *
25 | * @Author niujinpeng
26 | * @Date 2018/10/26 15:31
27 | */
28 | public class NioSelector {
29 |
30 | public static void main(String[] args) throws IOException {
31 | // 获取channel
32 | ServerSocketChannel channel = ServerSocketChannel.open();
33 | // channel是否阻塞
34 | channel.configureBlocking(false);
35 | // 监听88端口
36 | ServerSocket socket = channel.socket();
37 | socket.bind(new InetSocketAddress(83));
38 |
39 |
40 | // 创建选择器Selector
41 | Selector selector = Selector.open();
42 | // 像选择器中注册channel
43 | channel.register(selector, SelectionKey.OP_ACCEPT);
44 |
45 | while (true) {
46 | // 阻塞到有一个就绪
47 | int readyChannel = selector.select();
48 | if (readyChannel == 0) {
49 | continue;
50 | }
51 | Set selectionKeys = selector.selectedKeys();
52 | Iterator iterator = selectionKeys.iterator();
53 | while (iterator.hasNext()) {
54 | SelectionKey selectionKey = iterator.next();
55 | iterator.remove();
56 | // 是否可以接受
57 | if (selectionKey.isAcceptable()) {
58 | System.out.println("准备就绪");
59 | SelectableChannel selectableChannel = selectionKey.channel();
60 | ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectableChannel;
61 | SocketChannel socketChannel = serverSocketChannel.accept();
62 | socketChannel.configureBlocking(false);
63 | // 注册感兴趣事件-读取
64 | socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(2048));
65 | } else if (selectionKey.isConnectable()) {
66 | System.out.println("已连接");
67 |
68 | } else if (selectionKey.isReadable()) {
69 | System.out.println("可以读取");
70 |
71 | } else if (selectionKey.isWritable()) {
72 | System.out.println("可以写入");
73 |
74 | }
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/jdknio/NioSocketServer.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.jdknio;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.net.ServerSocket;
6 | import java.net.URLDecoder;
7 | import java.net.URLEncoder;
8 | import java.nio.ByteBuffer;
9 | import java.nio.channels.SelectableChannel;
10 | import java.nio.channels.SelectionKey;
11 | import java.nio.channels.Selector;
12 | import java.nio.channels.ServerSocketChannel;
13 | import java.nio.channels.SocketChannel;
14 | import java.util.Iterator;
15 |
16 | import org.slf4j.Logger;
17 | import org.slf4j.LoggerFactory;
18 |
19 | /**
20 | *
21 | * 使用Java NIO框架,实现一个支持多路复用IO的服务器端
22 | *
23 | * @Author niujinpeng
24 | * @Date 2018/10/16 0:53
25 | */
26 | public class NioSocketServer {
27 | /**
28 | * 日志
29 | */
30 | private static final Logger LOGGER = LoggerFactory.getLogger(NioSocketServer.class);
31 |
32 | public static void main(String[] args) throws IOException {
33 | ServerSocketChannel serverChannel = ServerSocketChannel.open();
34 | // 是否阻塞
35 | serverChannel.configureBlocking(false);
36 | ServerSocket serverSocket = serverChannel.socket();
37 | serverSocket.setReuseAddress(true);
38 | serverSocket.bind(new InetSocketAddress(83));
39 |
40 | Selector selector = Selector.open();
41 | // 服务器通道只能注册SelectionKey.OP_ACCEPT事件
42 | serverChannel.register(selector, SelectionKey.OP_ACCEPT);
43 |
44 | while (true) {
45 | // java程序对多路复用IO的支持也包括了阻塞模式 和非阻塞模式两种。
46 | if (selector.select(100) == 0) {
47 | //LOGGER.info("本次询问selector没有获取到任何准备好的事件");
48 | continue;
49 | }
50 |
51 | // 询问系统,所有获取到的事件类型
52 | Iterator selectionKeys = selector.selectedKeys().iterator();
53 | while (selectionKeys.hasNext()) {
54 | SelectionKey readKey = selectionKeys.next();
55 | // 上面获取到的readKey要移除,不然会一直存在selector.selectedKeys()的集合之中
56 | selectionKeys.remove();
57 |
58 | SelectableChannel selectableChannel = readKey.channel();
59 | if (readKey.isValid() && readKey.isAcceptable()) {
60 | LOGGER.info("--------------channel通道已经准备完毕-------------");
61 | /*
62 | * 当server socket channel通道已经准备好,就可以从server socket channel中获取socketchannel了
63 | * 拿到socket channel后,要做的事情就是马上到selector注册这个socket channel感兴趣的事情。
64 | * 否则无法监听到这个socket channel到达的数据
65 | * */
66 | ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectableChannel;
67 | SocketChannel socketChannel = serverSocketChannel.accept();
68 | registerSocketChannel(socketChannel, selector);
69 | } else if (readKey.isValid() && readKey.isConnectable()) {
70 | LOGGER.info("--------------socket channel 建立连接-------------");
71 | } else if (readKey.isValid() && readKey.isReadable()) {
72 | LOGGER.info("--------------socket channel 数据准备完成,可以开始读取-------------");
73 | try {
74 | readSocketChannel(readKey);
75 | } catch (Exception e) {
76 | LOGGER.error(e.getMessage());
77 | }
78 | }
79 | }
80 | }
81 |
82 | }
83 |
84 | /**
85 | * 在server socket channel接收到/准备好 一个新的 TCP连接后。
86 | * 就会向程序返回一个新的socketChannel。
87 | * 但是这个新的socket channel并没有在selector“选择器/代理器”中注册,
88 | * 所以程序还没法通过selector通知这个socket channel的事件。
89 | * 于是我们拿到新的socket channel后,要做的第一个事情就是到selector“选择器/代理器”中注册这个
90 | * socket channel感兴趣的事件
91 | *
92 | * @param socketChannel
93 | * @param selector
94 | * @throws Exception
95 | */
96 | private static void registerSocketChannel(SocketChannel socketChannel, Selector selector) {
97 | // 是否阻塞
98 | try {
99 | socketChannel.configureBlocking(false);
100 | // 读模式只能读,写模式可以同时读
101 | // socket通道可以且只可以注册三种事件SelectionKey.OP_READ | SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT
102 | socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(2048));
103 | } catch (IOException e) {
104 | LOGGER.info(e.toString(), e);
105 | }
106 |
107 | }
108 |
109 | private static void readSocketChannel(SelectionKey readKey) throws Exception {
110 | SocketChannel clientSocketChannel = (SocketChannel) readKey.channel();
111 | //获取客户端使用的端口
112 | InetSocketAddress sourceSocketAddress = (InetSocketAddress) clientSocketChannel.getRemoteAddress();
113 | int sourcePort = sourceSocketAddress.getPort();
114 |
115 | // 拿到这个socket channel使用的缓存区,准备读取数据
116 | // 解缓存区的用法概念,实际上重要的就是三个元素capacity,position和limit。
117 | ByteBuffer contextBytes = (ByteBuffer) readKey.attachment();
118 | // 通道的数据写入到【缓存区】
119 | // 由于之前设置了ByteBuffer的大小为2048 byte,所以可以存在写入不完的情况,需要调整
120 | int realLen = -1;
121 | try {
122 | realLen = clientSocketChannel.read(contextBytes);
123 | } catch (Exception e) {
124 | LOGGER.error(e.getMessage());
125 | clientSocketChannel.close();
126 | return;
127 | }
128 |
129 | // 如果缓存中没有数据
130 | if (realLen == -1) {
131 | LOGGER.warn("--------------缓存中没有数据-------------");
132 | return;
133 | }
134 |
135 | // 将缓存区读写状态模式进行切换
136 | contextBytes.flip();
137 | // 处理编码问题
138 | byte[] messageBytes = contextBytes.array();
139 | String messageEncode = new String(messageBytes, "UTF-8");
140 | String message = URLDecoder.decode(messageEncode, "UTF-8");
141 |
142 | // 接受到了"over"则清空buffer,并响应,否则不清空缓存,并还原Buffer写状态
143 | if (message.indexOf("over") != -1) {
144 | //清空已经读取的缓存,并从新切换为写状态(这里要注意clear()和capacity()两个方法的区别)
145 | contextBytes.clear();
146 | LOGGER.info("端口【" + sourcePort + "】客户端发来的信息:" + message);
147 | LOGGER.info("端口【" + sourcePort + "】客户端消息发送完毕");
148 | // 响应
149 | ByteBuffer sendBuffer = ByteBuffer.wrap(URLEncoder.encode("Done!", "UTF-8").getBytes());
150 | clientSocketChannel.write(sendBuffer);
151 | clientSocketChannel.close();
152 | } else {
153 | LOGGER.info("端口【" + sourcePort + "】客户端发来的信息还未完毕,继续接收");
154 | // limit和capacity的值一致,position的位置是realLen的位置
155 | contextBytes.position(realLen);
156 | contextBytes.limit(contextBytes.capacity());
157 | }
158 | }
159 |
160 |
161 | }
162 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/nio/SocketServerNioListen.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.nio;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.net.ServerSocket;
7 | import java.net.Socket;
8 | import java.net.SocketException;
9 | import java.net.SocketTimeoutException;
10 |
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | /**
15 | *
16 | * 非阻塞IO - 监听非阻塞
17 | * 通过设置超时时间实现
18 | *
19 | * @Author niujinpeng
20 | * @Date 2018/10/15 14:53
21 | */
22 | public class SocketServerNioListen {
23 |
24 | private static final Logger logger = LoggerFactory.getLogger(SocketServerNioListen.class);
25 |
26 | private static Object xWait = new Object();
27 |
28 | public static void main(String[] args) throws IOException {
29 | ServerSocket serverSocket = null;
30 |
31 | try {
32 | serverSocket = new ServerSocket(83);
33 | serverSocket.setSoTimeout(100);
34 | while (true) {
35 | Socket socket = null;
36 | try {
37 | socket = serverSocket.accept();
38 | } catch (SocketTimeoutException e) {
39 | synchronized (SocketServerNioListen.xWait) {
40 | logger.info("没有从底层接收到任务数据报文,等待10ms");
41 | SocketServerNioListen.xWait.wait(10);
42 | }
43 | continue;
44 | }
45 |
46 | InputStream input = socket.getInputStream();
47 | OutputStream output = socket.getOutputStream();
48 | Integer sourcePort = socket.getPort();
49 | int maxLen = 2048;
50 | byte[] contentBytes = new byte[maxLen];
51 | int realLen;
52 | StringBuffer message = new StringBuffer();
53 | // 读取的时候,程序会阻塞,知道系统把网络传过来的数据准备完毕
54 | while ((realLen = input.read(contentBytes, 0, maxLen)) != -1) {
55 | message.append(new String(contentBytes, 0, realLen));
56 | /**
57 | * 如果收到over,表示传送完毕
58 | */
59 | if (message.toString().endsWith("over")) {
60 | break;
61 | }
62 | }
63 |
64 | // 输出信息
65 | logger.info("服务器收到来自端口" + sourcePort + "的消息:" + message.toString());
66 | // 响应
67 | output.write("Done!".getBytes());
68 |
69 | output.close();
70 | input.close();
71 | socket.close();
72 | }
73 | } catch (SocketException | InterruptedException e) {
74 | logger.error(e.getMessage(), e);
75 | } finally {
76 | if (serverSocket != null) {
77 | serverSocket.close();
78 | }
79 | }
80 | }
81 |
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/nio/SocketServerNioListenAndRead.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.nio;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.net.ServerSocket;
7 | import java.net.Socket;
8 | import java.net.SocketException;
9 | import java.net.SocketTimeoutException;
10 |
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | /**
15 | *
16 | * 非阻塞IO - 监听非阻塞 - 读取非阻塞
17 | *
18 | * @Author niujinpeng
19 | * @Date 2018/10/15 14:53
20 | */
21 | public class SocketServerNioListenAndRead {
22 | /**
23 | * 日志
24 | */
25 | private static final Logger logger = LoggerFactory.getLogger(SocketServerNioListenAndRead.class);
26 | private static Object xWait = new Object();
27 |
28 | public static void main(String[] args) throws IOException {
29 | ServerSocket serverSocket = null;
30 |
31 | try {
32 | serverSocket = new ServerSocket(83);
33 | serverSocket.setSoTimeout(100);
34 | while (true) {
35 | Socket socket = null;
36 | try {
37 | socket = serverSocket.accept();
38 | } catch (SocketTimeoutException e) {
39 | synchronized (SocketServerNioListenAndRead.xWait) {
40 | logger.info("没有从底层接收到任务数据报文,等待10ms,,模拟事件X的处理时间");
41 | SocketServerNioListenAndRead.xWait.wait(10);
42 | }
43 | continue;
44 | }
45 |
46 | InputStream input = socket.getInputStream();
47 | OutputStream output = socket.getOutputStream();
48 | Integer sourcePort = socket.getPort();
49 | int maxLen = 2048;
50 | byte[] contentBytes = new byte[maxLen];
51 | int realLen;
52 | StringBuffer message = new StringBuffer();
53 |
54 | // 接收消息非阻塞实现
55 | socket.setSoTimeout(10);
56 |
57 | BIORead:
58 | while (true) {
59 | try {
60 | // 读取的时候,程序会阻塞,知道系统把网络传过来的数据准备完毕
61 | while ((realLen = input.read(contentBytes, 0, maxLen)) != -1) {
62 | message.append(new String(contentBytes, 0, realLen));
63 | /**
64 | * 如果收到over,表示传送完毕
65 | */
66 | if (message.toString().endsWith("over")) {
67 | break BIORead;
68 | }
69 | }
70 | } catch (SocketTimeoutException e) {
71 | //===========================================================
72 | // 执行到这里,说明本次read没有接收到任何数据流
73 | // 主线程在这里又可以做一些事情,记为Y
74 | //===========================================================
75 | logger.info("这次没有从底层接收到任务数据报文,等待10毫秒,模拟事件Y的处理时间");
76 | continue;
77 | }
78 |
79 | }
80 |
81 | // 输出信息
82 | logger.info("服务器收到来自端口" + sourcePort + "的消息:" + message.toString());
83 | // 响应
84 | output.write("Done!".getBytes());
85 |
86 | output.close();
87 | input.close();
88 | socket.close();
89 | }
90 | } catch (SocketException | InterruptedException e) {
91 | logger.error(e.getMessage(), e);
92 | } finally {
93 | if (serverSocket != null) {
94 | serverSocket.close();
95 | }
96 | }
97 | }
98 |
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/io/nio/SocketServerNioListenThread.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.io.nio;
2 |
3 | import java.io.InputStream;
4 | import java.io.OutputStream;
5 | import java.net.ServerSocket;
6 | import java.net.Socket;
7 | import java.net.SocketTimeoutException;
8 |
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | /**
13 | *
14 | * 非阻塞IO - 监听非阻塞 - 读取非阻塞
15 | * 通过加入线程的概念,让socket server能够在应用层面
16 | * 通过非阻塞的方式同时处理多个socket套接字
17 | *
18 | * 此时可以实现非阻塞的IO,但是因为调用了系统底层的阻塞同步IO,
19 | * 因此仍然没有从根本上解决问题
20 | *
21 | * @Author niujinpeng
22 | * @Date 2018/10/15 15:23
23 | */
24 | public class SocketServerNioListenThread {
25 |
26 | private static Object xWait = new Object();
27 |
28 | private static final Logger LOGGER = LoggerFactory.getLogger(SocketServerNioListenThread.class);
29 |
30 | public static void main(String[] args) throws Exception {
31 | ServerSocket serverSocket = new ServerSocket(83);
32 | serverSocket.setSoTimeout(100);
33 | try {
34 | while (true) {
35 | Socket socket = null;
36 | try {
37 | socket = serverSocket.accept();
38 | } catch (SocketTimeoutException e1) {
39 | //===========================================================
40 | // 执行到这里,说明本次accept没有接收到任何TCP连接
41 | // 主线程在这里就可以做一些事情,记为X
42 | //===========================================================
43 | synchronized (SocketServerNioListenThread.xWait) {
44 | LOGGER.info("这次没有从底层接收到任何TCP连接,等待10毫秒,模拟事件X的处理时间");
45 | SocketServerNioListenThread.xWait.wait(10);
46 | }
47 | continue;
48 | }
49 | //当然业务处理过程可以交给一个线程(这里可以使用线程池),并且线程的创建是很耗资源的。
50 | //最终改变不了.accept()只能一个一个接受socket连接的情况
51 | SocketServerThread socketServerThread = new SocketServerThread(socket);
52 | new Thread(socketServerThread).start();
53 | }
54 | } catch (Exception e) {
55 | LOGGER.error(e.getMessage(), e);
56 | } finally {
57 | if (serverSocket != null) {
58 | serverSocket.close();
59 | }
60 | }
61 | }
62 | }
63 |
64 | /**
65 | * 当然,接收到客户端的socket后,业务的处理过程可以交给一个线程来做。
66 | * 但还是改变不了socket被一个一个的做accept()的情况。
67 | *
68 | * @author niujinpeng
69 | */
70 | class SocketServerThread implements Runnable {
71 |
72 | /**
73 | * 日志
74 | */
75 | private static final Logger LOGGER = LoggerFactory.getLogger(SocketServerThread.class);
76 |
77 | private Socket socket;
78 |
79 | public SocketServerThread(Socket socket) {
80 | this.socket = socket;
81 | }
82 |
83 | @Override
84 | public void run() {
85 | InputStream in = null;
86 | OutputStream out = null;
87 | try {
88 | in = socket.getInputStream();
89 | out = socket.getOutputStream();
90 | Integer sourcePort = socket.getPort();
91 | int maxLen = 2048;
92 | byte[] contextBytes = new byte[maxLen];
93 | int realLen;
94 | StringBuffer message = new StringBuffer();
95 | //下面我们收取信息(设置成非阻塞方式,这样read信息的时候,又可以做一些其他事情)
96 | this.socket.setSoTimeout(10);
97 | BIORead:
98 | while (true) {
99 | try {
100 | while ((realLen = in.read(contextBytes, 0, maxLen)) != -1) {
101 | message.append(new String(contextBytes, 0, realLen));
102 | /*
103 | * 我们假设读取到“over”关键字,
104 | * 表示客户端的所有信息在经过若干次传送后,完成
105 | * */
106 | if (message.indexOf("over") != -1) {
107 | break BIORead;
108 | }
109 | }
110 | } catch (SocketTimeoutException e2) {
111 | //===========================================================
112 | // 执行到这里,说明本次read没有接收到任何数据流
113 | // 主线程在这里又可以做一些事情,记为Y
114 | //===========================================================
115 | LOGGER.info("这次没有从底层接收到任务数据报文,等待10毫秒,模拟事件Y的处理时间");
116 | continue;
117 | }
118 | }
119 | //下面打印信息
120 | Long threadId = Thread.currentThread().getId();
121 | LOGGER.info("服务器(线程:" + threadId + ")收到来自于端口:" + sourcePort + "的信息:" + message);
122 |
123 | //下面开始发送信息
124 | out.write("回发响应信息!".getBytes());
125 |
126 | //关闭
127 | out.close();
128 | in.close();
129 | this.socket.close();
130 | } catch (Exception e) {
131 | LOGGER.error(e.getMessage(), e);
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jdk/ModCountExceptionDemo.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jdk;
2 |
3 | import java.lang.Thread.State;
4 | import java.util.ArrayList;
5 | import java.util.Collections;
6 | import java.util.Iterator;
7 | import java.util.List;
8 | import java.util.concurrent.Phaser;
9 |
10 | import org.junit.Test;
11 |
12 | /**
13 | * 并发修改异常的绕过方式
14 | *
15 | * @author github.com/niumoo
16 | * @date 2021/02/11
17 | */
18 | public class ModCountExceptionDemo {
19 |
20 | @Test
21 | public void updateCollections() {
22 | List list = new ArrayList<>();
23 | Collections.addAll(list, "Hello", "World", "C++", "Java");
24 |
25 | list.listIterator();
26 | Iterator iterator = list.iterator();
27 | System.out.println(iterator.next());
28 | System.out.println(iterator.next());
29 | list.remove("C++");
30 | System.out.println(iterator.next());
31 | }
32 |
33 | @Test
34 | public void updateCollectionsFor() {
35 | List list = new ArrayList<>();
36 | Collections.addAll(list, "Hello", "World", "C++", "Java");
37 |
38 | list.listIterator();
39 | Iterator iterator = list.iterator();
40 | System.out.println(iterator.next());
41 | System.out.println(iterator.next());
42 | list.remove("C++");
43 | // 40 多亿次遍历,溢出到负数,继续溢出到原值
44 | for (int n = Integer.MIN_VALUE; n < Integer.MAX_VALUE; n++) { ((ArrayList)list).trimToSize(); }
45 | System.out.println(iterator.next());
46 | }
47 |
48 | @Test
49 | public void updateCollectionThread() {
50 | List list = new ArrayList<>();
51 | Collections.addAll(list, "Hello", "World", "C++", "Java");
52 |
53 | list.listIterator();
54 | Iterator iterator = list.iterator();
55 | System.out.println(iterator.next());
56 | System.out.println(iterator.next());
57 |
58 | // 开始操作
59 | list.set(2, "Java");
60 | Phaser phaser = new Phaser(2);
61 | Thread main = Thread.currentThread();
62 | new Thread(() -> {
63 | synchronized (System.out) {
64 | phaser.arriveAndDeregister();
65 | while (main.getState() != State.BLOCKED) {
66 | try {
67 | Thread.sleep(100);
68 | } catch (InterruptedException e) {
69 | e.printStackTrace();
70 | }
71 | }
72 | list.remove(3);
73 | }
74 | }).start();
75 | phaser.arriveAndAwaitAdvance();
76 |
77 | System.out.println(iterator.next());
78 |
79 | // 输出集合
80 | System.out.println(list);
81 |
82 | /**
83 | * 得到输出
84 | *
85 | * Hello
86 | * World
87 | * Java
88 | * [Hello, World, Java]
89 | */
90 | }
91 |
92 | @Test
93 | public void updateCollectionsObject() {
94 | List list = new ArrayList<>();
95 | Collections.addAll(list, "Hello", "World", "C++", "Java");
96 |
97 | list.listIterator();
98 | Iterator iterator = list.iterator();
99 | System.out.println(iterator.next());
100 | System.out.println(iterator.next());
101 |
102 | // 开始操作
103 | ((List)list).set(2, new Object() {
104 | public String toString() {
105 | String s = list.get(3);
106 | list.remove(this);
107 | return s;
108 | }
109 | });
110 |
111 | System.out.println(iterator.next());
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jdk/annotation/JdkAnnotation.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jdk.annotation;
2 |
3 | /**
4 | *
5 | * Java自带的几个注解
6 | *
7 | * @Author niujinpeng
8 | * @Date 2019/4/1 13:10
9 | */
10 | public class JdkAnnotation {
11 |
12 | /**
13 | * 抑制警告
14 | */
15 | @SuppressWarnings(":deprecated")
16 | public void test() {
17 | deparecated();
18 | }
19 |
20 | /**
21 | * @Deprecated 废弃方法
22 | */
23 | @Deprecated
24 | public void deparecated() {
25 | System.out.println("废弃方法");
26 | }
27 |
28 | /**
29 | * 方法重写
30 | *
31 | * @return
32 | */
33 | @Override
34 | public String toString() {
35 | return "JdkAnnotation{}";
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jdk/annotation/PersonAnon.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jdk.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | *
11 | * 自定义注解
12 | *
13 | * @interface 意味着实现了 java.lang.annotation.Annotation 接口
14 | * @Documented 类和方法的Annotation在缺省情况下是不出现在javadoc中的。
15 | * 如果使用@Documented修饰该Annotation, 则表示它可以出现在javadoc中。
16 | * 定义Annotation时,@Documented可有可无;若没有定义,则Annotation不会出现在javadoc中。
17 | * @Target 定义注解可以使用的位置。
18 | * 若有@Target,则该Annotation只能用于它所指定的地方;若没有@Target,则该Annotation可以用于任何地方。
19 | * @Retention 可有可无。若没有@Retention,则默认是RetentionPolicy.CLASS。
20 | *
21 | * @Author niujinpeng
22 | * @Date 2019/4/1 13:16
23 | */
24 | @Documented
25 | @Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) // 可用位置
26 | @Retention(RetentionPolicy.RUNTIME) // RetentionPolicy.SOURCE OR RetentionPolicy.CLASS OR RetentionPolicy.RUNTIME
27 | public @interface PersonAnon {
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jdk/thread/CallableFutureTest.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jdk.thread;
2 |
3 | import java.util.concurrent.Callable;
4 | import java.util.concurrent.ExecutionException;
5 | import java.util.concurrent.ExecutorService;
6 | import java.util.concurrent.Executors;
7 | import java.util.concurrent.Future;
8 |
9 | public class CallableFutureTest {
10 | @SuppressWarnings("unchecked")
11 | public static void main(String[] args) throws ExecutionException, InterruptedException {
12 | CallableFutureTest test = new CallableFutureTest();
13 |
14 | // 创建一个线程池
15 | ExecutorService pool = Executors.newFixedThreadPool(2);
16 | // 创建两个有返回值的任务
17 | Callable c1 = test.new MyCallable("A");
18 | Callable c2 = test.new MyCallable("B");
19 |
20 | // 执行任务并获取Future对象
21 | Future f1 = pool.submit(c1);
22 | Future f2 = pool.submit(c2);
23 |
24 | // 从Future对象上获取任务的返回值,并输出到控制台
25 | System.out.println(">>>" + f1.get().toString());
26 | System.out.println(">>>" + f2.get().toString());
27 |
28 | // 关闭线程池
29 | pool.shutdown();
30 | }
31 |
32 | @SuppressWarnings("unchecked")
33 | class MyCallable implements Callable {
34 | private String name;
35 |
36 | MyCallable(String name) {
37 | this.name = name;
38 | }
39 |
40 | @Override
41 | public Object call() throws Exception {
42 | return name + "任务返回的内容";
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jdk/thread/ExecutorTest.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jdk.thread;
2 |
3 | import java.util.concurrent.ExecutorService;
4 | import java.util.concurrent.Executors;
5 | import java.util.concurrent.ThreadPoolExecutor;
6 |
7 | /**
8 | *
9 | *
10 | * @Author niujinpeng
11 | * @Date 2018/12/4 10:33
12 | */
13 | public class ExecutorTest {
14 |
15 | public static ExecutorService executorService = Executors.newFixedThreadPool(50);
16 |
17 |
18 | public static void main(String[] args) {
19 | executorService.submit(new ThreadTest());
20 | int threadCount = ((ThreadPoolExecutor) executorService).getActiveCount();
21 | int poolSize = ((ThreadPoolExecutor) executorService).getPoolSize();
22 | System.out.println("当前线程数量:" + threadCount + ",当前池中线程数:" + poolSize);
23 | }
24 | }
25 |
26 | class ThreadTest implements Runnable{
27 |
28 | @Override
29 | public void run() {
30 | System.out.println("启动了");
31 | while (true){
32 |
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jvm/ConsumeCpu.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jvm;
2 |
3 | import java.util.Arrays;
4 | import java.util.Random;
5 |
6 | /**
7 | *
8 | * 消耗CPU的程序
9 | *
10 | * @Author niujinpeng
11 | * @Date 2019/3/20 18:02
12 | */
13 | public class ConsumeCpu {
14 |
15 | public static void main(String[] args) {
16 | while (true) {
17 | int[] arr = new int[10000000];
18 | for (int i = 0; i < 10000000; i++) {
19 | arr[i] = new Random().nextInt(10000000);
20 | }
21 | System.out.println("生成完成");
22 | Arrays.sort(arr);
23 | System.out.println("排序完成");
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jvm/DeadLock.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jvm;
2 |
3 | public class DeadLock {
4 |
5 | public static void main(String[] args) {
6 | start();
7 | }
8 |
9 | public static void start() {
10 | new Thread(() -> {
11 | System.out.print("thread1 starting....");
12 | synchronized (DeadLock.class) {
13 | System.out.println("Deadlock deadlock");
14 | try {
15 | Thread.sleep(1000);
16 | } catch (InterruptedException e) {
17 | e.printStackTrace();
18 | }
19 | synchronized (Object.class) {
20 | System.out.println("Deadlock object");
21 | }
22 | }
23 | }).start();
24 |
25 | new Thread(() -> {
26 | System.out.print("thread2 starting....");
27 | synchronized (Object.class) {
28 | System.out.println("Deadlock object");
29 | try {
30 | Thread.sleep(1000);
31 | } catch (InterruptedException e) {
32 | e.printStackTrace();
33 | }
34 | synchronized (DeadLock.class) {
35 | System.out.println("Deadlock deadlock");
36 | }
37 | }
38 | }).start();
39 | }
40 |
41 | }
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jvm/MonitoringTest.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jvm;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStreamReader;
5 |
6 | /**
7 | *
8 | *
9 | * @Author niujinpeng
10 | * @Date 2018/11/26 14:15
11 | */
12 | public class MonitoringTest {
13 |
14 |
15 | /**
16 | * 线程死循环演示
17 | */
18 | public static void createBusyThread() {
19 | Thread thread = new Thread(new Runnable() {
20 | @Override
21 | public void run() {
22 | while (true) {
23 |
24 | }
25 | }
26 | }, "testBusyThread");
27 | thread.start();
28 | }
29 |
30 | /**
31 | * 线程锁等待演示
32 | *
33 | * @param lock
34 | */
35 | public static void createLockThread(final Object lock) {
36 | Thread thread = new Thread(new Runnable() {
37 | @Override
38 | public void run() {
39 | synchronized (lock) {
40 | try {
41 | lock.wait();
42 | } catch (InterruptedException e) {
43 | e.printStackTrace();
44 | }
45 | }
46 | }
47 | },"testLockThread");
48 | thread.start();
49 | }
50 |
51 | public static void main(String[] args) throws Exception {
52 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
53 | br.readLine();
54 | createBusyThread();
55 | br.readLine();
56 | Object obj = new Object();
57 | createLockThread(obj);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jvm/OOMObject.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jvm;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * 用于演示内存占用情况
8 | */
9 | public class OOMObject {
10 | /**
11 | * 内存占位符对象,一个OOMObject大约占64KB
12 | */
13 | public byte[] placeholder = new byte[64 * 1024];
14 |
15 | public static void fillHeap(int num) throws InterruptedException {
16 | List list = new ArrayList();
17 | for (int i = 0; i < num; i++) {
18 | // 稍作延时,令监视曲线的变化更加明显
19 | Thread.sleep(50);
20 | list.add(new OOMObject());
21 | }
22 | System.gc();
23 | }
24 |
25 | public static void main(String[] args) throws Exception {
26 | // fillHeap(1000);
27 |
28 | // OutOfMemoryError
29 | // List list = new ArrayList();
30 | // while (true){
31 | // list.add(new OOMObject());
32 | // }
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jvm/RuntimeExec.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jvm;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 |
7 | /**
8 | *
9 | *
10 | * @Author niujinpeng
11 | * @Date 2018/11/26 15:17
12 | */
13 | public class RuntimeExec {
14 |
15 | public static void main(String[] args) throws IOException {
16 | Process process = Runtime.getRuntime().exec("ipconfig");
17 | BufferedReader bis = new BufferedReader(new InputStreamReader(process.getInputStream()));
18 | String line = null;
19 | while ((line = bis.readLine()) != null) {
20 | System.out.println(line);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jvm/StackOverflow.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jvm;
2 |
3 | /**
4 | *
5 | *
6 | * @Author niujinpeng
7 | * @Date 2019/3/22 14:23
8 | */
9 | public class StackOverflow {
10 | public static void main(String[] args) {
11 | System.out.println(count(0));
12 | }
13 |
14 | public static int count(int i) {
15 | System.out.println(i);
16 | return i + count(i + 1);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/jvm/SynAddRunalbe.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.jvm;
2 |
3 | /**
4 | * 线程死锁等待演示
5 | */
6 | public class SynAddRunalbe implements Runnable {
7 | int a, b;
8 |
9 | public SynAddRunalbe(int a, int b) {
10 | this.a = a;
11 | this.b = b;
12 | }
13 |
14 | @Override
15 | public void run() {
16 | synchronized (Integer.valueOf(a)) {
17 | synchronized (Integer.valueOf(b)) {
18 | System.out.println(a + b);
19 | }
20 | }
21 | }
22 |
23 |
24 | public static void main(String[] args) {
25 | for (int i = 0; i < 100; i++) {
26 | new Thread(new SynAddRunalbe(1, 2)).start();
27 | new Thread(new SynAddRunalbe(2, 1)).start();
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/other/GeneratorTextImage.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.other;
2 |
3 |
4 | import java.awt.*;
5 | import java.awt.image.BufferedImage;
6 | import java.io.File;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 |
10 | import javax.imageio.ImageIO;
11 |
12 | /**
13 | *
14 | * 根据图片生成字符图案
15 | * 1.图片大小缩放
16 | * 2.遍历图片像素点
17 | * 3.获取图片像素点亮度
18 | * 4.匹配字符
19 | * 5.输出图案
20 | *
21 | * @author niujinpeng
22 | * @website www.codingme.net
23 | * @date 2019-02-25 23:03:01
24 | */
25 |
26 | public class GeneratorTextImage {
27 | private static final char[] PIXEL = {'@', '#', '8', '&', 'o', ':', '*', '.', ' '};
28 |
29 | public static void main(String[] args) throws Exception {
30 | // 图片缩放
31 | BufferedImage bufferedImage = makeSmallImage("java-lab/src/main/resources/banner.jpg");
32 | // 输出
33 | printImage(bufferedImage);
34 | }
35 |
36 | public static void printImage(BufferedImage image) throws IOException {
37 | int width = image.getWidth();
38 | int height = image.getHeight();
39 | for (int i = 0; i < height; i++) {
40 | for (int j = 0; j < width; j++) {
41 | int rgb = image.getRGB(j, i);
42 | Color color = new Color(rgb);
43 | int red = color.getRed();
44 | int green = color.getGreen();
45 | int blue = color.getBlue();
46 | // 一个用于计算RGB像素点亮度的公式
47 | Double luminace = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
48 | double index = luminace / (Math.ceil(255 / PIXEL.length) + 0.5);
49 | System.out.print(PIXEL[(int)(Math.floor(index))]);
50 | }
51 | System.out.println();
52 | }
53 | }
54 |
55 | public static BufferedImage makeSmallImage(String srcImageName) throws Exception {
56 | File srcImageFile = new File(srcImageName);
57 | if (srcImageFile == null) {
58 | System.out.println("文件不存在");
59 | return null;
60 | }
61 | FileOutputStream fileOutputStream = null;
62 | BufferedImage tagImage = null;
63 | Image srcImage = null;
64 | try {
65 | srcImage = ImageIO.read(srcImageFile);
66 | int srcWidth = srcImage.getWidth(null);// 原图片宽度
67 | int srcHeight = srcImage.getHeight(null);// 原图片高度
68 | int dstMaxSize = 90;// 目标缩略图的最大宽度/高度,宽度与高度将按比例缩写
69 | int dstWidth = srcWidth;// 缩略图宽度
70 | int dstHeight = srcHeight;// 缩略图高度
71 | float scale = 0;
72 | // 计算缩略图的宽和高
73 | if (srcWidth > dstMaxSize) {
74 | dstWidth = dstMaxSize;
75 | scale = (float)srcWidth / (float)dstMaxSize;
76 | dstHeight = Math.round((float)srcHeight / scale);
77 | }
78 | srcHeight = dstHeight;
79 | if (srcHeight > dstMaxSize) {
80 | dstHeight = dstMaxSize;
81 | scale = (float)srcHeight / (float)dstMaxSize;
82 | dstWidth = Math.round((float)dstWidth / scale);
83 | }
84 | // 生成缩略图
85 | tagImage = new BufferedImage(dstWidth, dstHeight, BufferedImage.TYPE_INT_RGB);
86 | tagImage.getGraphics().drawImage(srcImage, 0, 0, dstWidth, dstHeight, null);
87 | return tagImage;
88 | } finally {
89 | if (fileOutputStream != null) {
90 | try {
91 | fileOutputStream.close();
92 | } catch (Exception e) {
93 | }
94 | fileOutputStream = null;
95 | }
96 | tagImage = null;
97 | srcImage = null;
98 | System.gc();
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/rmi/Search.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.rmi;
2 |
3 | import java.rmi.Remote;
4 | import java.rmi.RemoteException;
5 |
6 | /**
7 | * 定义一个远程接口
8 | *
9 | * @author github.com/niumoo
10 | * @date 2021/04/04
11 | */
12 | public interface Search extends Remote {
13 | User query(String userId) throws RemoteException;
14 | }
15 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/rmi/SearchClient.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.rmi;
2 |
3 | import java.rmi.Naming;
4 |
5 | /**
6 | * @author darcy
7 | * @date 2021/04/04
8 | */
9 | public class SearchClient {
10 | public static void main(String args[]) {
11 | User answer;
12 | String value = "1";
13 | try {
14 | // lookup method to find reference of remote object
15 | Search access = (Search)Naming.lookup("rmi://localhost:1900/search");
16 | answer = access.query(value);
17 | System.out.println("query:" + value);
18 | System.out.println("result:" + answer);
19 | } catch (Exception ae) {
20 | System.out.println(ae);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/rmi/SearchQuery.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.rmi;
2 |
3 | import java.rmi.RemoteException;
4 | import java.rmi.server.UnicastRemoteObject;
5 |
6 | /**
7 | * @author github.com/niumoo
8 | * @date 2021/04/04
9 | */
10 | public class SearchQuery extends UnicastRemoteObject implements Search {
11 | public SearchQuery() throws RemoteException {
12 | super();
13 | }
14 |
15 | @Override
16 | public User query(String userId) throws RemoteException {
17 | if ("1".equals(userId)) {
18 | return new User("金庸", 100);
19 | }
20 | return new User("好汉", 20);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/rmi/SearchServer.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.rmi;
2 |
3 | import java.rmi.Naming;
4 | import java.rmi.registry.LocateRegistry;
5 |
6 | /**
7 | * @author github.com/niumoo
8 | * @date 2021/04/04
9 | */
10 | public class SearchServer {
11 | public static void main(String[] args) {
12 | try {
13 | Search obj = new SearchQuery();
14 | LocateRegistry.createRegistry(1900);
15 | Naming.rebind("rmi://localhost:1900/search", obj);
16 | System.out.println("start server,port is 1900");
17 | } catch (Exception e) {
18 | e.printStackTrace();
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/rmi/User.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.rmi;
2 |
3 | import java.io.Serializable;
4 |
5 | import lombok.AllArgsConstructor;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | /**
10 | * @author niulang
11 | * @date 2021/04/04
12 | */
13 | @Data
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class User implements Serializable {
17 |
18 | private static final long serialVersionUID = -5176281163098592499L;
19 | private String name;
20 | private Integer age;
21 | }
22 |
--------------------------------------------------------------------------------
/java-lab/src/main/java/com/wdbyte/lab/tree/BitTree.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.lab.tree;
2 |
3 | import java.util.Stack;
4 |
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | /**
9 | *
10 | * 二叉树的遍历测试
11 | *
12 | * @Author niujinpeng
13 | * @Date 2019/4/10 10:33
14 | */
15 | @Data
16 | @Slf4j
17 | public class BitTree {
18 | private BitTree root;
19 | private T value;
20 | private BitTree left;
21 | private BitTree right;
22 |
23 | public BitTree(T value) {
24 | this.value = value;
25 | this.left = null;
26 | this.right = null;
27 | }
28 |
29 | public BitTree(T value, BitTree left, BitTree right) {
30 | this.value = value;
31 | this.left = left;
32 | this.right = right;
33 | }
34 |
35 | /**
36 | * 前序遍历
37 | *
38 | * @param rootTree
39 | */
40 | public void preRrder(BitTree rootTree) {
41 | if (rootTree != null) {
42 | System.out.println(rootTree.value);
43 | preRrder(rootTree.left);
44 | preRrder(rootTree.right);
45 | }
46 | }
47 |
48 | /**
49 | * 非递归前序遍历
50 | *
51 | * @param rootTree
52 | */
53 | public void stackOrder(BitTree rootTree) {
54 | Stack stack = new Stack();
55 | while (true) {
56 | while (rootTree != null) {
57 | System.out.println(rootTree.value);
58 | stack.push(rootTree);
59 | rootTree = rootTree.left;
60 | }
61 | if (stack.isEmpty()) {
62 | break;
63 | }
64 | BitTree bitTree = stack.pop();
65 | rootTree = bitTree.right;
66 | }
67 | }
68 |
69 | public static void main(String[] args) {
70 | BitTree rootTree = new BitTree<>(0);
71 | rootTree.setLeft(new BitTree(1, new BitTree(2), new BitTree(3)));
72 | rootTree.setRight(new BitTree(4, new BitTree(5), new BitTree(6)));
73 | rootTree.setRoot(rootTree);
74 | // 遍历
75 | rootTree.preRrder(rootTree.root);
76 | System.out.println("---------------");
77 | rootTree.stackOrder(rootTree.root);
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/java-lab/src/main/resources/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/niumoo/lab-notes/4c83a6cf055c97595f07ceb6dff83443d4dda5d5/java-lab/src/main/resources/banner.jpg
--------------------------------------------------------------------------------
/java-rmi/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | 4.0.0
7 | com.wdbyte
8 | java-rmi
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 8
13 | 8
14 |
15 |
16 |
--------------------------------------------------------------------------------
/java-rmi/src/main/java/com/wdbyte/rmi/client/RmiClient.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.rmi.client;
2 |
3 | import java.rmi.Naming;
4 |
5 | import com.wdbyte.rmi.server.User;
6 | import com.wdbyte.rmi.server.UserService;
7 |
8 | /**
9 | * @author https://www.wdbyte.com
10 | * @date 2021/05/08
11 | */
12 | public class RmiClient {
13 | public static void main(String args[]) {
14 | User answer;
15 | String userId = "00001";
16 | try {
17 | // lookup method to find reference of remote object
18 | UserService access = (UserService)Naming.lookup("rmi://localhost:1900/user");
19 | answer = access.findUser(userId);
20 | System.out.println("query:" + userId);
21 | System.out.println("result:" + answer);
22 | } catch (Exception ae) {
23 | System.out.println(ae);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/java-rmi/src/main/java/com/wdbyte/rmi/server/RmiServer.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.rmi.server;
2 |
3 | import java.rmi.Naming;
4 | import java.rmi.registry.LocateRegistry;
5 |
6 | /**
7 | * RMI Server 端
8 | *
9 | * @author https://www.wdbyte.com
10 | * @date 2021/05/08
11 | */
12 | public class RmiServer {
13 |
14 | public static void main(String[] args) {
15 | try {
16 | UserService userService = new UserServiceImpl();
17 | LocateRegistry.createRegistry(1900);
18 | Naming.rebind("rmi://localhost:1900/user", userService);
19 | System.out.println("start server,port is 1900");
20 | } catch (Exception e) {
21 | e.printStackTrace();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/java-rmi/src/main/java/com/wdbyte/rmi/server/User.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.rmi.server;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | *
7 | * @author www.wdbyte.com
8 | * @date 2021/05/08
9 | */
10 | public class User implements Serializable {
11 |
12 | private static final long serialVersionUID = 6490921832856589236L;
13 |
14 | private String name;
15 | private Integer age;
16 | private String skill;
17 |
18 | public String getName() {
19 | return name;
20 | }
21 |
22 | public void setName(String name) {
23 | this.name = name;
24 | }
25 |
26 | public Integer getAge() {
27 | return age;
28 | }
29 |
30 | public void setAge(Integer age) {
31 | this.age = age;
32 | }
33 |
34 | public String getSkill() {
35 | return skill;
36 | }
37 |
38 | public void setSkill(String skill) {
39 | this.skill = skill;
40 | }
41 |
42 | @Override
43 | public String toString() {
44 | return "User{" +
45 | "name='" + name + '\'' +
46 | ", age=" + age +
47 | ", skill='" + skill + '\'' +
48 | '}';
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/java-rmi/src/main/java/com/wdbyte/rmi/server/UserService.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.rmi.server;
2 |
3 | import java.rmi.Remote;
4 | import java.rmi.RemoteException;
5 |
6 |
7 | /**
8 | * RMI Server
9 | *
10 | * @author www.wdbyte.com
11 | * @date 2021/05/08
12 | */
13 | public interface UserService extends Remote {
14 |
15 | /**
16 | * 查找用户
17 | *
18 | * @param userId
19 | * @return
20 | * @throws RemoteException
21 | */
22 | User findUser(String userId) throws RemoteException;
23 | }
24 |
--------------------------------------------------------------------------------
/java-rmi/src/main/java/com/wdbyte/rmi/server/UserServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.rmi.server;
2 |
3 | import java.rmi.RemoteException;
4 | import java.rmi.server.UnicastRemoteObject;
5 |
6 | /**
7 | * @author www.wdbyte.com
8 | * @date 2021/05/08
9 | */
10 | public class UserServiceImpl extends UnicastRemoteObject implements UserService {
11 |
12 | protected UserServiceImpl() throws RemoteException {
13 | }
14 |
15 | @Override
16 | public User findUser(String userId) throws RemoteException {
17 | // 加载在查询
18 | if ("00001".equals(userId)) {
19 | User user = new User();
20 | user.setName("金庸");
21 | user.setAge(100);
22 | user.setSkill("写作");
23 | return user;
24 | }
25 | throw new RemoteException("查无此人");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/kryo-start/src/main/java/SomeClass.java:
--------------------------------------------------------------------------------
1 | import java.io.Serializable;
2 |
3 | public class SomeClass implements Serializable {
4 | private static final long serialVersionUID = -24181467826255255L;
5 | String value;
6 | }
--------------------------------------------------------------------------------
/poc-log4j2/Log4jTest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/niumoo/lab-notes/4c83a6cf055c97595f07ceb6dff83443d4dda5d5/poc-log4j2/Log4jTest.class
--------------------------------------------------------------------------------
/poc-log4j2/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.wdbyte
8 | poc-log4j2
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 8
13 | 8
14 |
15 |
16 |
17 |
18 |
19 | org.apache.logging.log4j
20 | log4j-core
21 | 2.17.1
22 |
23 |
24 |
25 | org.apache.logging.log4j
26 | log4j-api
27 | 2.17.1
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/poc-log4j2/src/main/java/Log4j2.java:
--------------------------------------------------------------------------------
1 | import org.apache.logging.log4j.LogManager;
2 | import org.apache.logging.log4j.Logger;
3 |
4 | /**
5 | * @author www.wdbyte.com
6 | */
7 | public class Log4j2 {
8 | private static final Logger logger = LogManager.getLogger(Log4j2.class);
9 |
10 | public static void main(String[] args) {
11 | System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
12 | logger.error("params:{}","${jndi:ldap://127.0.0.1:1389/Log4jTest}");
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 | com.wdbyte
7 | lab-notes
8 | 1.0-SNAPSHOT
9 |
10 | web-arthas
11 | web-goodskill
12 | java-lab
13 | java-algorithm
14 |
15 | pom
16 |
17 |
18 | 1.8
19 | 1.8
20 | 1.8
21 | 3.8.1
22 | 1.18.4
23 | 1.2.3
24 | 29.0-jre
25 | 4.13.1
26 |
27 |
28 |
29 |
30 |
31 | org.apache.commons
32 | commons-lang3
33 | ${commons-lang3.version}
34 |
35 |
36 |
37 |
38 | org.projectlombok
39 | lombok
40 | ${lombok.version}
41 | provided
42 |
43 |
44 |
45 | ch.qos.logback
46 | logback-classic
47 | ${logback.version}
48 |
49 |
50 |
51 |
52 | com.google.guava
53 | guava
54 | ${guava.version}
55 |
56 |
57 |
58 | junit
59 | junit
60 | ${junit4.version}
61 | compile
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/web-arthas/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | lab-notes
7 | com.wdbyte
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 | com.wdbyte
12 | web-arthas
13 | Arthas 使用测试案例
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-dependencies
20 | 2.1.13.RELEASE
21 | pom
22 | import
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-starter-web
32 |
33 |
34 | spring-boot-starter-json
35 | org.springframework.boot
36 |
37 |
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-test
43 | test
44 |
45 |
46 |
47 |
48 |
49 |
50 | org.springframework.boot
51 | spring-boot-maven-plugin
52 | 2.0.4.RELEASE
53 |
54 |
55 |
56 | repackage
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/web-arthas/src/main/java/com/wdbyte/arthas/Arthas.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.arthas;
2 |
3 | import java.util.HashSet;
4 | import java.util.concurrent.ExecutorService;
5 | import java.util.concurrent.Executors;
6 |
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | /**
10 | *
11 | * Arthas Demo
12 | * 公众号:未读代码
13 | *
14 | * @Author https://www.wdbyte.com
15 | */
16 | @Slf4j
17 | public class Arthas {
18 |
19 | private static HashSet hashSet = new HashSet();
20 | /** 线程池,大小1*/
21 | private static ExecutorService executorService = Executors.newFixedThreadPool(1);
22 |
23 | public static void start() {
24 | // 模拟 CPU 过高
25 | // cpu();
26 | // 模拟线程阻塞
27 | thread();
28 | // 模拟线程死锁
29 | deadThread();
30 | // 不断的向 hashSet 集合增加数据
31 | addHashSetThread();
32 | }
33 |
34 | /**
35 | * 不断的向 hashSet 集合添加数据
36 | */
37 | public static void addHashSetThread() {
38 | // 初始化常量
39 | new Thread(() -> {
40 | int count = 0;
41 | while (true) {
42 | try {
43 | hashSet.add("count" + count);
44 | Thread.sleep(10000);
45 | count++;
46 | } catch (InterruptedException e) {
47 | e.printStackTrace();
48 | }
49 | }
50 | }).start();
51 | }
52 |
53 | public static void cpu() {
54 | cpuHigh();
55 | cpuNormal();
56 | }
57 |
58 | /**
59 | * 极度消耗CPU的线程
60 | */
61 | private static void cpuHigh() {
62 | Thread thread = new Thread(() -> {
63 | while (true) {
64 | log.info("cpu start 100");
65 | }
66 | });
67 | // 添加到线程
68 | executorService.submit(thread);
69 | }
70 |
71 | /**
72 | * 普通消耗CPU的线程
73 | */
74 | private static void cpuNormal() {
75 | for (int i = 0; i < 10; i++) {
76 | new Thread(() -> {
77 | while (true) {
78 | log.info("cpu start");
79 | try {
80 | Thread.sleep(3000);
81 | } catch (InterruptedException e) {
82 | e.printStackTrace();
83 | }
84 | }
85 | }).start();
86 | }
87 | }
88 |
89 | /**
90 | * 模拟线程阻塞,向已经满了的线程池提交线程
91 | */
92 | private static void thread() {
93 | Thread thread = new Thread(() -> {
94 | while (true) {
95 | log.debug("thread start");
96 | try {
97 | Thread.sleep(3000);
98 | } catch (InterruptedException e) {
99 | e.printStackTrace();
100 | }
101 | }
102 | });
103 | // 添加到线程
104 | executorService.submit(thread);
105 | }
106 |
107 | /**
108 | * 死锁
109 | */
110 | private static void deadThread() {
111 | /** 创建资源 */
112 | Object resourceA = new Object();
113 | Object resourceB = new Object();
114 | // 创建线程
115 | Thread threadA = new Thread(() -> {
116 | synchronized (resourceA) {
117 | log.info(Thread.currentThread() + " get ResourceA");
118 | try {
119 | Thread.sleep(1000);
120 | } catch (InterruptedException e) {
121 | e.printStackTrace();
122 | }
123 | log.info(Thread.currentThread() + "waiting get resourceB");
124 | synchronized (resourceB) {
125 | log.info(Thread.currentThread() + " get resourceB");
126 | }
127 | }
128 | });
129 |
130 | Thread threadB = new Thread(() -> {
131 | synchronized (resourceB) {
132 | log.info(Thread.currentThread() + " get ResourceB");
133 | try {
134 | Thread.sleep(1000);
135 | } catch (InterruptedException e) {
136 | e.printStackTrace();
137 | }
138 | log.info(Thread.currentThread() + "waiting get resourceA");
139 | synchronized (resourceA) {
140 | log.info(Thread.currentThread() + " get resourceA");
141 | }
142 | }
143 | });
144 | threadA.start();
145 | threadB.start();
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/web-arthas/src/main/java/com/wdbyte/arthas/ArthasApplication.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.arthas;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 |
7 | @SpringBootApplication
8 | @Slf4j
9 | public class ArthasApplication {
10 |
11 | public static void main(String[] args) throws InterruptedException {
12 | SpringApplication.run(ArthasApplication.class, args);
13 | Arthas.start();
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/web-arthas/src/main/java/com/wdbyte/arthas/HotCode.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.arthas;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Random;
5 | import java.util.UUID;
6 |
7 | /**
8 | *
9 | * 模拟热点代码
10 | *
11 | * @Author https://www.wdbyte.com
12 | */
13 | public class HotCode {
14 |
15 | private static volatile int value;
16 |
17 | private static Object array;
18 |
19 | public static void main(String[] args) {
20 | while (true) {
21 | hotmethod1();
22 | hotmethod2();
23 | hotmethod3();
24 | allocate();
25 | }
26 | }
27 |
28 | /**
29 | * 生成 6万长度的数组
30 | */
31 | private static void allocate() {
32 | array = new int[6 * 1000];
33 | array = new Integer[6 * 1000];
34 | }
35 |
36 | /**
37 | * 生成一个UUID
38 | */
39 | private static void hotmethod3() {
40 | ArrayList list = new ArrayList<>();
41 | UUID uuid = UUID.randomUUID();
42 | String str = uuid.toString().replace("-", "");
43 | list.add(str);
44 | }
45 |
46 | /**
47 | * 数字累加
48 | */
49 | private static void hotmethod2() {
50 | value++;
51 | }
52 |
53 | /**
54 | * 生成一个随机数
55 | */
56 | private static void hotmethod1() {
57 | Random random = new Random();
58 | int anInt = random.nextInt();
59 | }
60 |
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/web-arthas/src/main/java/com/wdbyte/arthas/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.arthas.controller;
2 |
3 | import java.util.HashMap;
4 |
5 | import com.wdbyte.arthas.service.UserServiceImpl;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | /**
12 | *
13 | *
14 | * @Author https://www.wdbyte.com
15 | */
16 | @RestController
17 | @Slf4j
18 | public class UserController {
19 |
20 | @Autowired
21 | private UserServiceImpl userService;
22 |
23 | @GetMapping(value = "/user")
24 | public HashMap getUser(Integer uid) throws Exception {
25 | // 模拟用户查询
26 | userService.get(uid);
27 | HashMap hashMap = new HashMap<>();
28 | hashMap.put("uid", uid);
29 | hashMap.put("name", "name" + uid);
30 | return hashMap;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/web-arthas/src/main/java/com/wdbyte/arthas/service/UserServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.arthas.service;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.stereotype.Service;
5 |
6 | /**
7 | *
8 | *
9 | * @Author https://www.wdbyte.com
10 | */
11 | @Service
12 | @Slf4j
13 | public class UserServiceImpl {
14 |
15 | public void get(Integer uid) throws Exception {
16 | check(uid);
17 | service(uid);
18 | redis(uid);
19 | mysql(uid);
20 | }
21 |
22 | public void service(Integer uid) throws Exception {
23 | int count = 0;
24 | for (int i = 0; i < 10; i++) {
25 | count += i;
26 | }
27 | log.info("com.wdbyte.goodskill.service end {}", count);
28 | }
29 |
30 | public void redis(Integer uid) throws Exception {
31 | int count = 0;
32 | for (int i = 0; i < 10000; i++) {
33 | count += i;
34 | }
35 | log.info("redis end {}", count);
36 | }
37 |
38 | public void mysql(Integer uid) throws Exception {
39 | long count = 0;
40 | for (int i = 0; i < 10000000; i++) {
41 | count += i;
42 | }
43 | log.info("mysql end {}", count);
44 | }
45 |
46 | public boolean check(Integer uid) throws Exception {
47 | if (uid == null || uid < 0) {
48 | log.error("uid不正确,uid:{}", uid);
49 | throw new Exception("uid不正确");
50 | }
51 | return true;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/web-arthas/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8080
3 | servlet:
4 | context-path: /
5 |
--------------------------------------------------------------------------------
/web-arthas/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}: %msg%n
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ${catalina.base}/logs/logback-info.log.%d{yyyy-MM-dd}
20 |
21 | 60
22 |
23 |
24 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}: %msg%n
25 |
26 |
27 | INFO
28 | ACCEPT
29 | DENY
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | ${catalina.base}/logs/logback-error.log.%d{yyyy-MM-dd}
39 |
40 | 60
41 |
42 |
43 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}: %msg%n
44 |
45 |
46 | ERROR
47 | ACCEPT
48 | DENY
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/web-goodskill/README.md:
--------------------------------------------------------------------------------
1 | ## 简单的秒杀系统的实现
2 |
3 | ### 知识点
4 | - 唯一主键
5 | - Redis 分布式锁
6 | - 秒杀商品缓存
7 | - 用户订单异步处理
--------------------------------------------------------------------------------
/web-goodskill/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | lab-notes
7 | com.wdbyte
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 | web-goodskill
12 |
13 |
14 |
15 |
16 | org.springframework.boot
17 | spring-boot-dependencies
18 | 2.1.13.RELEASE
19 | pom
20 | import
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-web
30 |
31 |
32 | spring-boot-starter-json
33 | org.springframework.boot
34 |
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-test
41 | test
42 |
43 |
44 | org.springframework.boot
45 | spring-boot-starter-data-redis
46 |
47 |
48 |
49 |
50 |
51 |
52 | org.springframework.boot
53 | spring-boot-maven-plugin
54 | 2.0.4.RELEASE
55 |
56 |
57 |
58 | repackage
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/web-goodskill/src/main/java/README.md:
--------------------------------------------------------------------------------
1 | ## 简单的秒杀系统的实现
2 |
3 | ### 知识点
4 | - 唯一主键
5 | - Redis 分布式锁
6 | - 秒杀商品缓存
7 | - 用户订单异步处理
--------------------------------------------------------------------------------
/web-goodskill/src/main/java/com/wdbyte/goodskill/BootApplication.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.goodskill;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | /**
7 | * Springboot 启动
8 | *
9 | * @author https://www.wdbyte.com
10 | */
11 | @SpringBootApplication
12 | public class BootApplication {
13 |
14 | public static void main(String[] args) {
15 | SpringApplication.run(BootApplication.class, args);
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/web-goodskill/src/main/java/com/wdbyte/goodskill/controller/SkillController.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.goodskill.controller;
2 |
3 | import com.wdbyte.goodskill.service.SkillService;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | /**
9 | *
10 | * 简单的商品秒杀
11 | *
12 | *
13 | * @Author https://www.wdbyte.com
14 | * @Date 2019/3/20 11:33
15 | */
16 | @RestController
17 | public class SkillController {
18 |
19 | @Autowired
20 | private SkillService skillService;
21 |
22 | @GetMapping(value = "/sell/skill")
23 | public String skill(String product) {
24 | return skillService.skillProduct(product);
25 | }
26 |
27 | @GetMapping(value = "/sell/skill-redis")
28 | public String skillRedis(String product) {
29 | return skillService.skillProductByRedis(product);
30 | }
31 |
32 | @GetMapping(value = "/sell/skill/query")
33 | public String querySkillProductInfo(String product) {
34 | return skillService.querySkillProductInfo(product);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/web-goodskill/src/main/java/com/wdbyte/goodskill/service/SkillService.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.goodskill.service;
2 |
3 | /**
4 | *
5 | *
6 | * @Author https://www.wdbyte.com
7 | * @Date 2019/3/2011:36
8 | */
9 | public interface SkillService {
10 |
11 | String querySkillProductInfo(String productId);
12 |
13 | String skillProduct(String productId);
14 |
15 | String skillProductByRedis(String productId);
16 | }
17 |
--------------------------------------------------------------------------------
/web-goodskill/src/main/java/com/wdbyte/goodskill/service/impl/SkillServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.goodskill.service.impl;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import com.wdbyte.goodskill.service.SkillService;
7 | import com.wdbyte.goodskill.utils.KeyUtil;
8 | import com.wdbyte.goodskill.utils.RedisLock;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.stereotype.Service;
11 |
12 | /**
13 | *
14 | *
15 | * @Author https://www.wdbyte.com
16 | * @Date 2019/3/20 11:36
17 | */
18 | @Service
19 | public class SkillServiceImpl implements SkillService {
20 |
21 | @Autowired
22 | private RedisLock redisLock;
23 |
24 | private static Integer TIME_OUT = 10 * 1000;
25 |
26 | /** 商品和抢购数量 */
27 | static Map products;
28 | /** 库存 */
29 | static Map stock;
30 | /** 订单 */
31 | static Map orders;
32 | static {
33 | products = new HashMap<>();
34 | stock = new HashMap<>();
35 | orders = new HashMap<>();
36 | products.put("iphonex", 10000);
37 | stock.put("iphonex", 10000);
38 | }
39 |
40 | public String getProductInfo(String product) {
41 | return " iphonex 抢购活动火爆进行中,限量:" + products.get(product) + "份,目前剩余" + stock.get(product) + "份,下单人数:"
42 | + orders.size() + "人!";
43 | }
44 |
45 | @Override
46 | public String querySkillProductInfo(String product) {
47 | return getProductInfo(product);
48 | }
49 |
50 | @Override
51 | public String skillProduct(String product) {
52 | // 查询库存
53 | if (stock.get(product) == 0) {
54 | return "活动已经结束!";
55 | }
56 | // 下单
57 | orders.put(KeyUtil.getUniqueKey(), product);
58 | // 扣库存
59 | try {
60 | // 模拟时间消耗
61 | Thread.sleep(10);
62 | } catch (InterruptedException e) {
63 | e.printStackTrace();
64 | }
65 | stock.put(product, stock.get(product) - 1);
66 | return "恭喜你强到了 " + product;
67 | }
68 |
69 | @Override
70 | public String skillProductByRedis(String product) {
71 | long value = System.currentTimeMillis() + TIME_OUT;
72 | if (!redisLock.lock(product, String.valueOf(value))) {
73 | return "当前人数过于火爆";
74 | }
75 | // 查询库存
76 | if (stock.get(product) == 0) {
77 | return "活动已经结束!";
78 | }
79 | // 下单
80 | orders.put(KeyUtil.getUniqueKey(), product);
81 | // 扣库存
82 | try {
83 | // 模拟时间消耗
84 | Thread.sleep(10);
85 | } catch (InterruptedException e) {
86 | e.printStackTrace();
87 | }
88 | stock.put(product, stock.get(product) - 1);
89 | redisLock.unlock(product, String.valueOf(value));
90 | return "恭喜你强到了 " + product;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/web-goodskill/src/main/java/com/wdbyte/goodskill/utils/KeyUtil.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.goodskill.utils;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 | import java.util.Random;
6 | import java.util.UUID;
7 |
8 | /**
9 | *
10 | *
11 | *
12 | * @Author https://www.wdbyte.com
13 | * @Date 2019/1/31 17:28
14 | */
15 | public class KeyUtil {
16 |
17 | private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
18 | /**
19 | * 生成唯一主键 格式:时间+随机数
20 | *
21 | * @return
22 | */
23 | public static synchronized String getUniqueKey() {
24 | Random random = new Random();
25 | Integer randNumber = random.nextInt(900000) + 100000;
26 | return sdf.format(new Date()) + String.valueOf(randNumber);
27 | }
28 |
29 | public static void main(String[] args) {
30 | long start = System.currentTimeMillis();
31 | for (int i = 0; i < 1000000; i++) {
32 | System.out.println(UUID.randomUUID());
33 | }
34 | long end = System.currentTimeMillis();
35 | System.out.println(end-start);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/web-goodskill/src/main/java/com/wdbyte/goodskill/utils/RedisLock.java:
--------------------------------------------------------------------------------
1 | package com.wdbyte.goodskill.utils;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.apache.commons.lang3.StringUtils;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.data.redis.core.RedisTemplate;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | *
11 | * Redis 分布式锁的实现
12 | *
13 | * @Author https://www.wdbyte.com
14 | * @Date 2019/3/20 14:54
15 | */
16 | @Slf4j
17 | @Component
18 | public class RedisLock {
19 |
20 | @Autowired
21 | private RedisTemplate redisTemplate;
22 |
23 | public boolean lock(String key, String value) {
24 | // 没有锁直接加锁
25 | if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
26 | return true;
27 | }
28 | String currentValue = (String)redisTemplate.opsForValue().get(key);
29 | // 如果锁过期
30 | if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
31 | // 获取上一个锁的时间
32 | String oldValue = (String)redisTemplate.opsForValue().getAndSet(key, value);
33 | if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
34 | return true;
35 | }
36 | }
37 | return false;
38 | }
39 |
40 | public void unlock(String key, String value) {
41 | try {
42 | String currentValue = (String)redisTemplate.opsForValue().get(key);
43 | if (StringUtils.isNotEmpty(currentValue) && currentValue.equals(value)) {
44 | redisTemplate.opsForValue().getOperations().delete(key);
45 | }
46 | } catch (Exception e) {
47 | log.error("【redis分布式锁】解锁异常");
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/web-goodskill/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8080
3 | servlet:
4 | context-path: /
5 |
6 | spring:
7 | redis:
8 | database: 0
9 | host: 127.0.0.1
10 | port: 6379
11 | password:
12 | timeout: 10
13 | jedis:
14 | pool:
15 | max-active: 9
16 | max-wait: -1
17 | max-idle: 8
18 | min-idle: 0
19 |
--------------------------------------------------------------------------------
/web-goodskill/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}: %msg%n
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ${catalina.base}/logs/logback-info.log.%d{yyyy-MM-dd}
20 |
21 | 60
22 |
23 |
24 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}: %msg%n
25 |
26 |
27 | INFO
28 | ACCEPT
29 | DENY
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | ${catalina.base}/logs/logback-error.log.%d{yyyy-MM-dd}
39 |
40 | 60
41 |
42 |
43 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}: %msg%n
44 |
45 |
46 | ERROR
47 | ACCEPT
48 | DENY
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------