Initial commit

This commit is contained in:
2025-11-06 10:32:28 +08:00
commit 1f42e79061
112 changed files with 5101 additions and 0 deletions

29
Homework0520/.gitignore vendored Normal file
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings" defaultProject="true" />
</project>

View 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>

View 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());
}
}

View 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());
}
}

View 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());
}
}

View 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());
}
}

View 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());
}
}

View 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));
// 2flip() 和 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("=== 2flip() 和 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());
}
}

View 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("✗ 验证失败:票数统计有误");
}
}
}