Initial commit
This commit is contained in:
29
Homework0520/.gitignore
vendored
Normal file
29
Homework0520/.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
### IntelliJ IDEA ###
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
10
Homework0520/.idea/.gitignore
generated
vendored
Normal file
10
Homework0520/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# 依赖于环境的 Maven 主目录路径
|
||||
/mavenHomeManager.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
6
Homework0520/.idea/misc.xml
generated
Normal file
6
Homework0520/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
Homework0520/.idea/modules.xml
generated
Normal file
8
Homework0520/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/Homework0520.iml" filepath="$PROJECT_DIR$/Homework0520.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
4
Homework0520/.idea/vcs.xml
generated
Normal file
4
Homework0520/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings" defaultProject="true" />
|
||||
</project>
|
||||
11
Homework0520/Homework0520.iml
Normal file
11
Homework0520/Homework0520.iml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
62
Homework0520/src/BufferBasicOperations.java
Normal file
62
Homework0520/src/BufferBasicOperations.java
Normal file
@@ -0,0 +1,62 @@
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class BufferBasicOperations {
|
||||
public static void main(String[] args) {
|
||||
// 创建一个容量为10的ByteBuffer
|
||||
ByteBuffer buffer = ByteBuffer.allocate(10);
|
||||
System.out.println("初始状态:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 向缓冲区依次写入字节1, 2, 3, 4, 5
|
||||
buffer.put((byte) 1);
|
||||
buffer.put((byte) 2);
|
||||
buffer.put((byte) 3);
|
||||
buffer.put((byte) 4);
|
||||
buffer.put((byte) 5);
|
||||
System.out.println("\n写入数据后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 切换为读模式
|
||||
buffer.flip();
|
||||
System.out.println("\n切换为读模式后(flip):");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 读取并打印所有数据
|
||||
System.out.println("\n读取的数据:");
|
||||
while (buffer.hasRemaining()) {
|
||||
byte data = buffer.get();
|
||||
System.out.print(data + " ");
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
System.out.println("\n读取完成后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 清空缓冲区
|
||||
buffer.clear();
|
||||
System.out.println("\n清空缓冲区后(clear):");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 验证是否可重新写入
|
||||
buffer.put((byte) 100);
|
||||
buffer.put((byte) 200);
|
||||
System.out.println("\n重新写入数据后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 验证重新写入的数据
|
||||
buffer.flip();
|
||||
System.out.println("\n验证重新写入的数据:");
|
||||
while (buffer.hasRemaining()) {
|
||||
System.out.print(buffer.get() + " ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
// 打印缓冲区状态
|
||||
private static void printBufferStatus(ByteBuffer buffer) {
|
||||
System.out.println("Position: " + buffer.position() +
|
||||
", Limit: " + buffer.limit() +
|
||||
", Capacity: " + buffer.capacity() +
|
||||
", Remaining: " + buffer.remaining());
|
||||
}
|
||||
}
|
||||
65
Homework0520/src/BufferFlipCompact.java
Normal file
65
Homework0520/src/BufferFlipCompact.java
Normal file
@@ -0,0 +1,65 @@
|
||||
import java.nio.CharBuffer;
|
||||
|
||||
public class BufferFlipCompact {
|
||||
public static void main(String[] args) {
|
||||
// 创建一个容量为8的CharBuffer
|
||||
CharBuffer buffer = CharBuffer.allocate(8);
|
||||
System.out.println("初始状态:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 写入字符串"Hello"
|
||||
buffer.put("Hello");
|
||||
System.out.println("\n写入'Hello'后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 翻转缓冲区准备读取
|
||||
buffer.flip();
|
||||
System.out.println("\n翻转缓冲区后(flip):");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 读取前3个字符('H', 'e', 'l')
|
||||
System.out.println("\n读取前3个字符:");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
char c = buffer.get();
|
||||
System.out.print(c + " ");
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
System.out.println("\n读取3个字符后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 压缩缓冲区
|
||||
buffer.compact();
|
||||
System.out.println("\n压缩缓冲区后(compact):");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 再写入"World"
|
||||
buffer.put("World");
|
||||
System.out.println("\n写入'World'后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 翻转并打印最终缓冲区内容
|
||||
buffer.flip();
|
||||
System.out.println("\n最终缓冲区内容:");
|
||||
while (buffer.hasRemaining()) {
|
||||
System.out.print(buffer.get());
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
// 显示完整的缓冲区内容(包括未读取的部分)
|
||||
buffer.rewind(); // 回到开始位置
|
||||
System.out.println("\n完整缓冲区内容:");
|
||||
while (buffer.hasRemaining()) {
|
||||
System.out.print(buffer.get());
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
// 打印缓冲区状态
|
||||
private static void printBufferStatus(CharBuffer buffer) {
|
||||
System.out.println("Position: " + buffer.position() +
|
||||
", Limit: " + buffer.limit() +
|
||||
", Capacity: " + buffer.capacity() +
|
||||
", Remaining: " + buffer.remaining());
|
||||
}
|
||||
}
|
||||
105
Homework0520/src/BufferMarkInvalid.java
Normal file
105
Homework0520/src/BufferMarkInvalid.java
Normal file
@@ -0,0 +1,105 @@
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.InvalidMarkException;
|
||||
|
||||
public class BufferMarkInvalid {
|
||||
public static void main(String[] args) {
|
||||
// 创建一个容量为3的IntBuffer
|
||||
IntBuffer buffer = IntBuffer.allocate(3);
|
||||
System.out.println("初始状态:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 依次写入10、20
|
||||
buffer.put(10);
|
||||
buffer.put(20);
|
||||
System.out.println("\n写入10、20后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 在写入20后调用mark()
|
||||
buffer.mark();
|
||||
System.out.println("\n调用mark()后 (position=2):");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 写入30
|
||||
buffer.put(30);
|
||||
System.out.println("\n写入30后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 调用reset(),验证是否能成功
|
||||
try {
|
||||
buffer.reset();
|
||||
System.out.println("\n第一次reset()成功:");
|
||||
printBufferStatus(buffer);
|
||||
System.out.println("mark仍然有效,position回到标记位置2");
|
||||
} catch (InvalidMarkException e) {
|
||||
System.out.println("\n第一次reset()失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
// 清空缓冲区
|
||||
buffer.clear();
|
||||
System.out.println("\n清空缓冲区后(clear):");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 再次调用reset(),观察是否抛出InvalidMarkException
|
||||
try {
|
||||
buffer.reset();
|
||||
System.out.println("\nclear()后reset()成功 - 这不应该发生!");
|
||||
printBufferStatus(buffer);
|
||||
} catch (InvalidMarkException e) {
|
||||
System.out.println("\nclear()后reset()失败 (预期行为):");
|
||||
System.out.println("抛出InvalidMarkException: " + e.getMessage());
|
||||
System.out.println("原因: clear()方法会丢弃mark标记");
|
||||
}
|
||||
|
||||
// 演示其他会使mark失效的操作
|
||||
System.out.println("\n--- 演示其他使mark失效的场景 ---");
|
||||
|
||||
// 重新设置数据和标记
|
||||
buffer.clear();
|
||||
buffer.put(100).put(200);
|
||||
buffer.mark(); // 在position=2处标记
|
||||
buffer.put(300);
|
||||
|
||||
System.out.println("重新设置数据和标记后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 测试rewind()是否影响mark
|
||||
buffer.rewind();
|
||||
System.out.println("\n调用rewind()后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
try {
|
||||
buffer.reset();
|
||||
System.out.println("rewind()后reset()成功 - mark依然有效");
|
||||
printBufferStatus(buffer);
|
||||
} catch (InvalidMarkException e) {
|
||||
System.out.println("rewind()后reset()失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
// 测试flip()是否影响mark
|
||||
buffer.clear();
|
||||
buffer.put(1000).put(2000);
|
||||
buffer.mark(); // 标记
|
||||
buffer.put(3000);
|
||||
|
||||
buffer.flip(); // 准备读取
|
||||
System.out.println("\n调用flip()后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
try {
|
||||
buffer.reset();
|
||||
System.out.println("flip()后reset()成功");
|
||||
printBufferStatus(buffer);
|
||||
} catch (InvalidMarkException e) {
|
||||
System.out.println("flip()后reset()失败: " + e.getMessage());
|
||||
System.out.println("说明: flip()会丢弃mark标记");
|
||||
}
|
||||
}
|
||||
|
||||
// 打印缓冲区状态
|
||||
private static void printBufferStatus(IntBuffer buffer) {
|
||||
System.out.println("Position: " + buffer.position() +
|
||||
", Limit: " + buffer.limit() +
|
||||
", Capacity: " + buffer.capacity() +
|
||||
", Remaining: " + buffer.remaining());
|
||||
}
|
||||
}
|
||||
95
Homework0520/src/BufferMarkReset.java
Normal file
95
Homework0520/src/BufferMarkReset.java
Normal file
@@ -0,0 +1,95 @@
|
||||
import java.nio.CharBuffer;
|
||||
|
||||
public class BufferMarkReset {
|
||||
public static void main(String[] args) {
|
||||
// 创建一个容量为5的CharBuffer
|
||||
CharBuffer buffer = CharBuffer.allocate(5);
|
||||
System.out.println("初始状态:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 写入字符A
|
||||
buffer.put('A');
|
||||
System.out.println("\n写入字符A后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 写入字符B
|
||||
buffer.put('B');
|
||||
System.out.println("\n写入字符B后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 在写入B后调用mark()方法,此时position是2
|
||||
buffer.mark();
|
||||
System.out.println("\n调用mark()后 (position=2):");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 继续写入C、D、E直到缓冲区满
|
||||
buffer.put('C');
|
||||
buffer.put('D');
|
||||
buffer.put('E');
|
||||
System.out.println("\n继续写入C、D、E后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 调用reset()方法,验证position是否回到标记位置
|
||||
buffer.reset();
|
||||
System.out.println("\n调用reset()后:");
|
||||
printBufferStatus(buffer);
|
||||
System.out.println("验证: position已回到标记位置 2");
|
||||
|
||||
// 从position 2开始重新读取并打印后续字符
|
||||
// 首先需要调整limit以便能够读取
|
||||
buffer.limit(5); // 设置limit为容量,允许读取到末尾
|
||||
System.out.println("\n从position 2开始读取后续字符:");
|
||||
while (buffer.hasRemaining()) {
|
||||
char c = buffer.get();
|
||||
System.out.print("字符: " + c + " (position: " + buffer.position() + ")\n");
|
||||
}
|
||||
|
||||
// 演示完整的读取过程
|
||||
System.out.println("\n--- 完整演示 ---");
|
||||
buffer.clear(); // 重置缓冲区
|
||||
|
||||
// 重新写入数据
|
||||
buffer.put('A').put('B');
|
||||
buffer.mark(); // 在position=2处标记
|
||||
buffer.put('C').put('D').put('E');
|
||||
|
||||
// 切换到读模式
|
||||
buffer.flip();
|
||||
System.out.println("切换到读模式后:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 读取所有数据以验证内容
|
||||
System.out.println("完整内容:");
|
||||
while (buffer.hasRemaining()) {
|
||||
System.out.print(buffer.get() + " ");
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
// 注意:flip()方法会丢弃标记,所以需要重新设置
|
||||
// 将position设置到想要标记的位置,然后调用mark()
|
||||
buffer.position(2); // 移动到位置2
|
||||
buffer.mark(); // 重新标记
|
||||
System.out.println("\n重新设置标记在position=2:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 使用reset回到标记位置
|
||||
buffer.reset();
|
||||
System.out.println("\n使用reset()回到标记位置:");
|
||||
printBufferStatus(buffer);
|
||||
|
||||
// 从标记位置开始读取
|
||||
System.out.println("从标记位置开始读取:");
|
||||
while (buffer.hasRemaining()) {
|
||||
System.out.print(buffer.get() + " ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
// 打印缓冲区状态
|
||||
private static void printBufferStatus(CharBuffer buffer) {
|
||||
System.out.println("Position: " + buffer.position() +
|
||||
", Limit: " + buffer.limit() +
|
||||
", Capacity: " + buffer.capacity() +
|
||||
", Remaining: " + buffer.remaining());
|
||||
}
|
||||
}
|
||||
163
Homework0520/src/BufferMarkerReader.java
Normal file
163
Homework0520/src/BufferMarkerReader.java
Normal file
@@ -0,0 +1,163 @@
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class BufferMarkerReader {
|
||||
|
||||
/**
|
||||
* 使用ByteBuffer读取一段字节数据的方法
|
||||
* 在读取到特定字节(如0xFF)时设置标记
|
||||
* 继续读取后续字节,直到遇到下一个0xFF
|
||||
* 若未找到第二个0xFF,则回退到标记位置
|
||||
*
|
||||
* @param buffer 要读取的ByteBuffer
|
||||
* @param marker 标记字节,默认为0xFF
|
||||
* @return 读取的字节数组,如果回退则返回null
|
||||
*/
|
||||
public static byte[] readWithMarker(ByteBuffer buffer, byte marker) {
|
||||
if (!buffer.hasRemaining()) {
|
||||
System.out.println("缓冲区没有剩余数据可读");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 查找第一个标记字节
|
||||
boolean firstMarkerFound = false;
|
||||
int markPosition = -1;
|
||||
|
||||
// 寻找第一个0xFF
|
||||
while (buffer.hasRemaining()) {
|
||||
byte currentByte = buffer.get();
|
||||
if (currentByte == marker) {
|
||||
firstMarkerFound = true;
|
||||
markPosition = buffer.position() - 1; // 标记字节的位置
|
||||
buffer.mark(); // 在找到第一个标记后设置mark
|
||||
System.out.println("找到第一个标记字节 0xFF,位置: " + markPosition);
|
||||
System.out.println("设置标记,当前position: " + buffer.position());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!firstMarkerFound) {
|
||||
System.out.println("未找到第一个标记字节 0xFF");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 收集从第一个标记到第二个标记之间的数据
|
||||
ByteBuffer tempBuffer = ByteBuffer.allocate(buffer.remaining() + 1);
|
||||
tempBuffer.put(marker); // 包含第一个标记字节
|
||||
|
||||
// 继续读取,寻找第二个标记字节
|
||||
boolean secondMarkerFound = false;
|
||||
while (buffer.hasRemaining()) {
|
||||
byte currentByte = buffer.get();
|
||||
tempBuffer.put(currentByte);
|
||||
|
||||
if (currentByte == marker) {
|
||||
secondMarkerFound = true;
|
||||
System.out.println("找到第二个标记字节 0xFF,位置: " + (buffer.position() - 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (secondMarkerFound) {
|
||||
// 找到第二个标记,返回两个标记之间的数据(包含标记字节)
|
||||
tempBuffer.flip();
|
||||
byte[] result = new byte[tempBuffer.remaining()];
|
||||
tempBuffer.get(result);
|
||||
System.out.println("成功读取数据,长度: " + result.length);
|
||||
return result;
|
||||
} else {
|
||||
// 未找到第二个标记,回退到第一个标记位置
|
||||
try {
|
||||
buffer.reset();
|
||||
System.out.println("未找到第二个标记字节,回退到标记位置");
|
||||
System.out.println("回退后的position值: " + buffer.position());
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
System.out.println("回退失败: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 测试用例1:包含两个0xFF的数据
|
||||
System.out.println("=== 测试用例1:包含两个0xFF的数据 ===");
|
||||
byte[] testData1 = {0x01, 0x02, (byte)0xFF, 0x03, 0x04, 0x05, (byte)0xFF, 0x06, 0x07};
|
||||
ByteBuffer buffer1 = ByteBuffer.wrap(testData1);
|
||||
|
||||
System.out.println("原始数据:");
|
||||
printByteArray(testData1);
|
||||
System.out.println("初始buffer状态:");
|
||||
printBufferStatus(buffer1);
|
||||
|
||||
byte[] result1 = readWithMarker(buffer1, (byte)0xFF);
|
||||
if (result1 != null) {
|
||||
System.out.println("读取结果:");
|
||||
printByteArray(result1);
|
||||
}
|
||||
System.out.println("最终buffer状态:");
|
||||
printBufferStatus(buffer1);
|
||||
|
||||
System.out.println("\n=== 测试用例2:只有一个0xFF的数据 ===");
|
||||
byte[] testData2 = {0x01, 0x02, (byte)0xFF, 0x03, 0x04, 0x05, 0x06};
|
||||
ByteBuffer buffer2 = ByteBuffer.wrap(testData2);
|
||||
|
||||
System.out.println("原始数据:");
|
||||
printByteArray(testData2);
|
||||
System.out.println("初始buffer状态:");
|
||||
printBufferStatus(buffer2);
|
||||
|
||||
byte[] result2 = readWithMarker(buffer2, (byte)0xFF);
|
||||
if (result2 != null) {
|
||||
System.out.println("读取结果:");
|
||||
printByteArray(result2);
|
||||
}
|
||||
System.out.println("最终buffer状态:");
|
||||
printBufferStatus(buffer2);
|
||||
|
||||
System.out.println("\n=== 测试用例3:没有0xFF的数据 ===");
|
||||
byte[] testData3 = {0x01, 0x02, 0x03, 0x04, 0x05};
|
||||
ByteBuffer buffer3 = ByteBuffer.wrap(testData3);
|
||||
|
||||
System.out.println("原始数据:");
|
||||
printByteArray(testData3);
|
||||
|
||||
byte[] result3 = readWithMarker(buffer3, (byte)0xFF);
|
||||
if (result3 != null) {
|
||||
System.out.println("读取结果:");
|
||||
printByteArray(result3);
|
||||
}
|
||||
|
||||
System.out.println("\n=== 测试用例4:连续的0xFF ===");
|
||||
byte[] testData4 = {0x01, (byte)0xFF, (byte)0xFF, 0x02, 0x03};
|
||||
ByteBuffer buffer4 = ByteBuffer.wrap(testData4);
|
||||
|
||||
System.out.println("原始数据:");
|
||||
printByteArray(testData4);
|
||||
|
||||
byte[] result4 = readWithMarker(buffer4, (byte)0xFF);
|
||||
if (result4 != null) {
|
||||
System.out.println("读取结果:");
|
||||
printByteArray(result4);
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助方法:打印字节数组
|
||||
private static void printByteArray(byte[] array) {
|
||||
System.out.print("[");
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
System.out.printf("0x%02X", array[i]);
|
||||
if (i < array.length - 1) {
|
||||
System.out.print(", ");
|
||||
}
|
||||
}
|
||||
System.out.println("]");
|
||||
}
|
||||
|
||||
// 打印缓冲区状态
|
||||
private static void printBufferStatus(ByteBuffer buffer) {
|
||||
System.out.println("Position: " + buffer.position() +
|
||||
", Limit: " + buffer.limit() +
|
||||
", Capacity: " + buffer.capacity() +
|
||||
", Remaining: " + buffer.remaining());
|
||||
}
|
||||
}
|
||||
245
Homework0520/src/BufferVerificationAndThinking.java
Normal file
245
Homework0520/src/BufferVerificationAndThinking.java
Normal file
@@ -0,0 +1,245 @@
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
|
||||
public class BufferVerificationAndThinking {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// (1)如何判断缓冲区是否还有剩余空间?
|
||||
testRemainingSpace();
|
||||
|
||||
System.out.println("\n" + "=".repeat(60));
|
||||
|
||||
// (2)flip() 和 rewind() 的区别
|
||||
testFlipVsRewind();
|
||||
|
||||
System.out.println("\n" + "=".repeat(60));
|
||||
|
||||
// (3)直接缓冲区与非直接缓冲区的性能差异
|
||||
testDirectVsNonDirectBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* (1)测试如何判断缓冲区是否还有剩余空间
|
||||
*/
|
||||
private static void testRemainingSpace() {
|
||||
System.out.println("=== (1)测试缓冲区剩余空间判断 ===");
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(5);
|
||||
System.out.println("创建容量为5的ByteBuffer:");
|
||||
printBufferInfo(buffer);
|
||||
|
||||
// 写入数据测试剩余空间
|
||||
System.out.println("\n逐步写入数据,观察剩余空间变化:");
|
||||
for (int i = 1; i <= 6; i++) {
|
||||
if (buffer.hasRemaining()) {
|
||||
buffer.put((byte) i);
|
||||
System.out.println("写入字节 " + i + " 后:");
|
||||
printBufferInfo(buffer);
|
||||
} else {
|
||||
System.out.println("尝试写入字节 " + i + ": 缓冲区已满,无法写入");
|
||||
printBufferInfo(buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 切换到读模式测试剩余数据
|
||||
buffer.flip();
|
||||
System.out.println("\n切换到读模式后:");
|
||||
printBufferInfo(buffer);
|
||||
|
||||
System.out.println("\n逐步读取数据,观察剩余数据变化:");
|
||||
while (buffer.hasRemaining()) {
|
||||
byte data = buffer.get();
|
||||
System.out.println("读取字节 " + data + " 后:");
|
||||
printBufferInfo(buffer);
|
||||
}
|
||||
|
||||
if (!buffer.hasRemaining()) {
|
||||
System.out.println("所有数据已读取完毕");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (2)测试flip()和rewind()的区别
|
||||
*/
|
||||
private static void testFlipVsRewind() {
|
||||
System.out.println("=== (2)flip() 和 rewind() 的区别 ===");
|
||||
|
||||
CharBuffer buffer = CharBuffer.allocate(10);
|
||||
|
||||
// 写入一些数据
|
||||
buffer.put("Hello");
|
||||
System.out.println("写入'Hello'后的状态:");
|
||||
printBufferInfo(buffer);
|
||||
|
||||
// 测试flip()
|
||||
System.out.println("\n--- 测试flip()方法 ---");
|
||||
CharBuffer buffer1 = buffer.duplicate(); // 创建副本用于测试
|
||||
buffer1.flip();
|
||||
System.out.println("调用flip()后:");
|
||||
printBufferInfo(buffer1);
|
||||
System.out.println("flip()的作用: position->0, limit->原position值, 准备从头读取已写入的数据");
|
||||
|
||||
// 读取数据验证flip的效果
|
||||
System.out.println("使用flip()后读取数据:");
|
||||
while (buffer1.hasRemaining()) {
|
||||
System.out.print(buffer1.get());
|
||||
}
|
||||
System.out.println();
|
||||
printBufferInfo(buffer1);
|
||||
|
||||
// 测试rewind()
|
||||
System.out.println("\n--- 测试rewind()方法 ---");
|
||||
CharBuffer buffer2 = buffer.duplicate(); // 创建副本用于测试
|
||||
buffer2.rewind();
|
||||
System.out.println("调用rewind()后:");
|
||||
printBufferInfo(buffer2);
|
||||
System.out.println("rewind()的作用: position->0, limit保持不变, 重新从头开始");
|
||||
|
||||
// 使用rewind后的缓冲区
|
||||
System.out.println("使用rewind()后尝试读取数据 (limit仍为capacity):");
|
||||
int readCount = 0;
|
||||
while (buffer2.hasRemaining() && readCount < 5) { // 只读5个字符,避免读取未初始化数据
|
||||
char c = buffer2.get();
|
||||
if (c != 0) { // 只打印非零字符
|
||||
System.out.print(c);
|
||||
}
|
||||
readCount++;
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
// 关键区别总结
|
||||
System.out.println("\n--- 关键区别总结 ---");
|
||||
System.out.println("flip(): position=0, limit=原position (准备读取已写入的数据)");
|
||||
System.out.println("rewind(): position=0, limit=不变 (重新开始,但limit通常是capacity)");
|
||||
System.out.println("使用场景:");
|
||||
System.out.println(" flip() - 写模式切换到读模式");
|
||||
System.out.println(" rewind() - 重新读取整个缓冲区或重新写入");
|
||||
}
|
||||
|
||||
/**
|
||||
* (3)测试直接缓冲区与非直接缓冲区的性能差异
|
||||
*/
|
||||
private static void testDirectVsNonDirectBuffer() {
|
||||
System.out.println("=== (3)直接缓冲区与非直接缓冲区的性能测试 ===");
|
||||
|
||||
int bufferSize = 1024 * 1024; // 1MB
|
||||
int iterations = 1000;
|
||||
|
||||
// 创建直接缓冲区和非直接缓冲区
|
||||
ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize);
|
||||
ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize);
|
||||
|
||||
System.out.println("缓冲区大小: " + bufferSize + " 字节");
|
||||
System.out.println("测试迭代次数: " + iterations);
|
||||
System.out.println();
|
||||
|
||||
// 检查缓冲区类型
|
||||
System.out.println("直接缓冲区检查: " + directBuffer.isDirect());
|
||||
System.out.println("堆缓冲区检查: " + heapBuffer.isDirect());
|
||||
System.out.println();
|
||||
|
||||
// 测试写入性能
|
||||
System.out.println("--- 写入性能测试 ---");
|
||||
|
||||
// 测试直接缓冲区写入性能
|
||||
long startTime = System.nanoTime();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
directBuffer.clear();
|
||||
for (int j = 0; j < bufferSize; j++) {
|
||||
directBuffer.put((byte) (j % 256));
|
||||
}
|
||||
}
|
||||
long directWriteTime = System.nanoTime() - startTime;
|
||||
|
||||
// 测试堆缓冲区写入性能
|
||||
startTime = System.nanoTime();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
heapBuffer.clear();
|
||||
for (int j = 0; j < bufferSize; j++) {
|
||||
heapBuffer.put((byte) (j % 256));
|
||||
}
|
||||
}
|
||||
long heapWriteTime = System.nanoTime() - startTime;
|
||||
|
||||
System.out.println("直接缓冲区写入时间: " + (directWriteTime / 1_000_000) + " ms");
|
||||
System.out.println("堆缓冲区写入时间: " + (heapWriteTime / 1_000_000) + " ms");
|
||||
System.out.println("写入性能比: " + String.format("%.2f", (double) heapWriteTime / directWriteTime));
|
||||
|
||||
// 测试读取性能
|
||||
System.out.println("\n--- 读取性能测试 ---");
|
||||
|
||||
// 准备数据
|
||||
directBuffer.clear();
|
||||
heapBuffer.clear();
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
byte value = (byte) (i % 256);
|
||||
directBuffer.put(value);
|
||||
heapBuffer.put(value);
|
||||
}
|
||||
|
||||
// 测试直接缓冲区读取性能
|
||||
startTime = System.nanoTime();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
directBuffer.flip();
|
||||
while (directBuffer.hasRemaining()) {
|
||||
directBuffer.get();
|
||||
}
|
||||
directBuffer.rewind();
|
||||
}
|
||||
long directReadTime = System.nanoTime() - startTime;
|
||||
|
||||
// 测试堆缓冲区读取性能
|
||||
startTime = System.nanoTime();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
heapBuffer.flip();
|
||||
while (heapBuffer.hasRemaining()) {
|
||||
heapBuffer.get();
|
||||
}
|
||||
heapBuffer.rewind();
|
||||
}
|
||||
long heapReadTime = System.nanoTime() - startTime;
|
||||
|
||||
System.out.println("直接缓冲区读取时间: " + (directReadTime / 1_000_000) + " ms");
|
||||
System.out.println("堆缓冲区读取时间: " + (heapReadTime / 1_000_000) + " ms");
|
||||
System.out.println("读取性能比: " + String.format("%.2f", (double) heapReadTime / directReadTime));
|
||||
|
||||
// 性能差异原因分析
|
||||
System.out.println("\n--- 性能差异原因分析 ---");
|
||||
System.out.println("1. 内存分配位置:");
|
||||
System.out.println(" 直接缓冲区: 分配在JVM堆外的本地内存中");
|
||||
System.out.println(" 非直接缓冲区: 分配在JVM堆内存中");
|
||||
|
||||
System.out.println("\n2. I/O操作效率:");
|
||||
System.out.println(" 直接缓冲区: 减少一次内存拷贝 (本地内存 -> 系统调用)");
|
||||
System.out.println(" 非直接缓冲区: 需要额外拷贝 (JVM堆 -> 本地内存 -> 系统调用)");
|
||||
|
||||
System.out.println("\n3. 垃圾回收影响:");
|
||||
System.out.println(" 直接缓冲区: 不受GC直接影响,但清理较复杂");
|
||||
System.out.println(" 非直接缓冲区: 受GC影响,但分配和释放更快");
|
||||
|
||||
System.out.println("\n4. 使用建议:");
|
||||
System.out.println(" 直接缓冲区: 适用于长期存在、频繁I/O操作的大缓冲区");
|
||||
System.out.println(" 非直接缓冲区: 适用于短期、小规模的内存操作");
|
||||
|
||||
// 内存使用情况
|
||||
System.out.println("\n--- 内存使用情况 ---");
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
System.out.println("JVM堆内存使用情况:");
|
||||
System.out.println(" 最大内存: " + (runtime.maxMemory() / 1024 / 1024) + " MB");
|
||||
System.out.println(" 总内存: " + (runtime.totalMemory() / 1024 / 1024) + " MB");
|
||||
System.out.println(" 空闲内存: " + (runtime.freeMemory() / 1024 / 1024) + " MB");
|
||||
System.out.println(" 已用内存: " + ((runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024) + " MB");
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印缓冲区详细信息
|
||||
*/
|
||||
private static void printBufferInfo(java.nio.Buffer buffer) {
|
||||
System.out.println(" Position: " + buffer.position() +
|
||||
" | Limit: " + buffer.limit() +
|
||||
" | Capacity: " + buffer.capacity() +
|
||||
" | Remaining: " + buffer.remaining() +
|
||||
" | HasRemaining: " + buffer.hasRemaining());
|
||||
}
|
||||
}
|
||||
142
Homework0520/src/TicketSystem.java
Normal file
142
Homework0520/src/TicketSystem.java
Normal file
@@ -0,0 +1,142 @@
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class TicketSystem {
|
||||
private int ticketCount = 100; // 初始票数
|
||||
private final ReentrantLock lock = new ReentrantLock(); // 可重入锁
|
||||
private int totalSold = 0; // 已售票数统计
|
||||
|
||||
/**
|
||||
* 卖票方法 - 线程安全
|
||||
*
|
||||
* @param sellerId 售票员ID
|
||||
* @return true表示成功卖出一张票,false表示没有票了
|
||||
*/
|
||||
public boolean sellTicket(String sellerId) {
|
||||
lock.lock(); // 获取锁
|
||||
try {
|
||||
if (ticketCount > 0) {
|
||||
// 模拟卖票过程的耗时
|
||||
try {
|
||||
Thread.sleep(10); // 模拟卖票耗时
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
ticketCount--;
|
||||
totalSold++;
|
||||
int currentTicket = 100 - ticketCount; // 当前卖出的是第几张票
|
||||
|
||||
System.out.println(sellerId + " 卖出第 " + currentTicket + " 张票,剩余票数: " + ticketCount);
|
||||
return true;
|
||||
} else {
|
||||
System.out.println(sellerId + " 尝试卖票,但已无票可售");
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock(); // 确保锁被释放
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取剩余票数
|
||||
*/
|
||||
public int getRemainingTickets() {
|
||||
lock.lock();
|
||||
try {
|
||||
return ticketCount;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已售票数
|
||||
*/
|
||||
public int getTotalSold() {
|
||||
lock.lock();
|
||||
try {
|
||||
return totalSold;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 售票员线程类
|
||||
*/
|
||||
static class TicketSeller implements Runnable {
|
||||
private final TicketSystem ticketSystem;
|
||||
private final String sellerId;
|
||||
|
||||
public TicketSeller(TicketSystem ticketSystem, String sellerId) {
|
||||
this.ticketSystem = ticketSystem;
|
||||
this.sellerId = sellerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println(sellerId + " 开始售票");
|
||||
|
||||
while (true) {
|
||||
boolean sold = ticketSystem.sellTicket(sellerId);
|
||||
if (!sold) {
|
||||
// 没有票了,结束售票
|
||||
break;
|
||||
}
|
||||
|
||||
// 模拟售票间隔
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(sellerId + " 结束售票");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TicketSystem ticketSystem = new TicketSystem();
|
||||
|
||||
System.out.println("=== 卖票系统启动 ===");
|
||||
System.out.println("初始票数: " + ticketSystem.getRemainingTickets());
|
||||
|
||||
// 创建3个售票员线程
|
||||
Thread seller1 = new Thread(new TicketSeller(ticketSystem, "售票员1"));
|
||||
Thread seller2 = new Thread(new TicketSeller(ticketSystem, "售票员2"));
|
||||
Thread seller3 = new Thread(new TicketSeller(ticketSystem, "售票员3"));
|
||||
|
||||
// 启动线程
|
||||
long startTime = System.currentTimeMillis();
|
||||
seller1.start();
|
||||
seller2.start();
|
||||
seller3.start();
|
||||
|
||||
// 等待所有线程结束
|
||||
try {
|
||||
seller1.join();
|
||||
seller2.join();
|
||||
seller3.join();
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("主线程被中断");
|
||||
}
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
|
||||
// 输出最终结果
|
||||
System.out.println("\n=== 售票结束 ===");
|
||||
System.out.println("剩余票数: " + ticketSystem.getRemainingTickets());
|
||||
System.out.println("已售票数: " + ticketSystem.getTotalSold());
|
||||
System.out.println("总耗时: " + (endTime - startTime) + " 毫秒");
|
||||
|
||||
// 验证结果
|
||||
if (ticketSystem.getRemainingTickets() == 0 && ticketSystem.getTotalSold() == 100) {
|
||||
System.out.println("✓ 验证成功:所有票都已售出,且没有重复售票");
|
||||
} else {
|
||||
System.out.println("✗ 验证失败:票数统计有误");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user