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
Final/.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
Final/.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
Final/.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
Final/.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$/Final.iml" filepath="$PROJECT_DIR$/Final.iml" />
</modules>
</component>
</project>

124
Final/.idea/uiDesigner.xml generated Normal file
View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

4
Final/.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>

11
Final/Final.iml Normal file
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,108 @@
package aio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;
public class AIOChatClient {
private static final String HOST = "127.0.0.1";
private static final int PORT = 8888;
private AsynchronousSocketChannel clientChannel;
private CountDownLatch latch;
public void start() throws Exception {
clientChannel = AsynchronousSocketChannel.open();
latch = new CountDownLatch(1);
clientChannel.connect(new InetSocketAddress(HOST, PORT), null, new CompletionHandler<Void, Object>() {
@Override
public void completed(Void result, Object attachment) {
System.out.println("成功连接到服务器。现在可以开始聊天了(输入 'exit' 退出)。");
startRead();
startWrite();
}
@Override
public void failed(Throwable exc, Object attachment) {
System.err.println("连接服务器失败: " + exc.getMessage());
latch.countDown();
}
});
latch.await();
}
private void startRead() {
ByteBuffer buffer = ByteBuffer.allocate(1024);
clientChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
if (result > 0) {
attachment.flip();
String message = StandardCharsets.UTF_8.decode(attachment).toString();
System.out.println(message);
attachment.clear();
} else if (result == -1) {
handleDisconnect();
return;
}
if (clientChannel.isOpen()) {
clientChannel.read(attachment, attachment, this);
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.err.println("读取数据失败: " + exc.getMessage());
handleDisconnect();
}
});
}
private void startWrite() {
new Thread(() -> {
BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
try {
String message;
while ((message = consoleReader.readLine()) != null) {
if ("exit".equalsIgnoreCase(message.trim())) {
break;
}
ByteBuffer buffer = StandardCharsets.UTF_8.encode(message);
clientChannel.write(buffer, null, new CompletionHandler<Integer, Object>() {
@Override
public void completed(Integer result, Object attachment) {}
@Override
public void failed(Throwable exc, Object attachment) {
System.err.println("发送消息失败: " + exc.getMessage());
handleDisconnect();
}
});
}
} catch (IOException e) {
e.printStackTrace();
} finally {
handleDisconnect();
}
}).start();
}
private void handleDisconnect() {
try {
if (clientChannel.isOpen()) {
clientChannel.close();
System.out.println("与服务器的连接已断开。");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
}
public static void main(String[] args) {
try {
new AIOChatClient().start();
} catch (Exception e) {
System.err.println("客户端启动时发生错误。");
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,127 @@
package aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
public class AIOChatServer {
private static final int PORT = 8888;
private AsynchronousServerSocketChannel serverSocketChannel;
private final CopyOnWriteArrayList<AsynchronousSocketChannel> clients = new CopyOnWriteArrayList<>();
public void start() {
try {
AsynchronousChannelGroup group = AsynchronousChannelGroup.withThreadPool(Executors.newFixedThreadPool(10));
serverSocketChannel = AsynchronousServerSocketChannel.open(group);
serverSocketChannel.bind(new InetSocketAddress(PORT));
System.out.println("服务器已启动,监听端口:" + PORT);
serverSocketChannel.accept(null, new AcceptHandler());
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
private class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, Object> {
@Override
public void completed(AsynchronousSocketChannel clientChannel, Object attachment) {
serverSocketChannel.accept(null, this);
clients.add(clientChannel);
try {
System.out.println("客户端 [" + clientChannel.getRemoteAddress() + "] 已连接。当前在线人数:" + clients.size());
} catch (IOException e) {
e.printStackTrace();
}
ByteBuffer buffer = ByteBuffer.allocate(1024);
clientChannel.read(buffer, new ClientSession(clientChannel, buffer), new ReadWriteHandler());
}
@Override
public void failed(Throwable exc, Object attachment) {
System.out.println("接受连接失败:" + exc);
}
}
private class ReadWriteHandler implements CompletionHandler<Integer, ClientSession> {
@Override
public void completed(Integer result, ClientSession session) {
if (result > 0) {
session.buffer.flip();
String receivedMessage = StandardCharsets.UTF_8.decode(session.buffer).toString().trim();
if (!receivedMessage.isEmpty()) {
String messageToSend;
try {
messageToSend = "客户端 [" + session.clientChannel.getRemoteAddress() + "] 说: " + receivedMessage;
System.out.println("正在广播: " + messageToSend);
broadcast(messageToSend, session.clientChannel);
} catch (IOException e) {
e.printStackTrace();
}
}
session.buffer.clear();
session.clientChannel.read(session.buffer, session, this);
} else if (result == -1) {
handleDisconnect(session.clientChannel);
}
}
@Override
public void failed(Throwable exc, ClientSession session) {
System.out.println("读写数据时发生错误:" + exc.getMessage());
handleDisconnect(session.clientChannel);
}
}
private void broadcast(String message, AsynchronousSocketChannel sender) {
ByteBuffer initialBuffer = StandardCharsets.UTF_8.encode(message);
for (AsynchronousSocketChannel client : clients) {
if (client.isOpen() && !client.equals(sender)) {
ByteBuffer bufferForWriting = initialBuffer.duplicate();
class WriteContext {
final AsynchronousSocketChannel clientChannel;
final ByteBuffer buffer;
WriteContext(AsynchronousSocketChannel client, ByteBuffer buf) {
this.clientChannel = client;
this.buffer = buf;
}
}
WriteContext context = new WriteContext(client, bufferForWriting);
client.write(bufferForWriting, context, new CompletionHandler<Integer, WriteContext>() {
@Override
public void completed(Integer result, WriteContext attachment) {
// 如果缓冲区中还有剩余数据,说明是一次“部分写”,需要继续发送
if (attachment.buffer.hasRemaining()) {
attachment.clientChannel.write(attachment.buffer, attachment, this);
}
}
@Override
public void failed(Throwable exc, WriteContext attachment) {
System.err.println("向客户端 " + attachment.clientChannel + " 广播消息失败: " + exc);
handleDisconnect(attachment.clientChannel);
}
});
}
}
}
private void handleDisconnect(AsynchronousSocketChannel clientChannel) {
clients.remove(clientChannel);
try {
System.out.println("客户端 [" + clientChannel.getRemoteAddress() + "] 已断开连接。当前在线人数:" + clients.size());
clientChannel.close();
} catch (IOException e) {
}
}
private static class ClientSession {
AsynchronousSocketChannel clientChannel;
ByteBuffer buffer;
public ClientSession(AsynchronousSocketChannel clientChannel, ByteBuffer buffer) {
this.clientChannel = clientChannel;
this.buffer = buffer;
}
}
public static void main(String[] args) {
new AIOChatServer().start();
}
}

View File

@@ -0,0 +1,96 @@
package aio;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class AsyncQueueDemo {
public static void main(String[] args) throws InterruptedException {
final int QUEUE_CAPACITY = 10;
final int PRODUCER_COUNT = 3;
final int CONSUMER_COUNT = 5;
final int ITEMS_PER_PRODUCER = 20;
AsyncQueue<String> queue = new AsyncQueue<>(QUEUE_CAPACITY);
ExecutorService producerExecutor = Executors.newFixedThreadPool(PRODUCER_COUNT);
ExecutorService consumerExecutor = Executors.newFixedThreadPool(CONSUMER_COUNT);
AtomicInteger producedCount = new AtomicInteger(0);
AtomicInteger consumedCount = new AtomicInteger(0);
System.out.println("启动 " + PRODUCER_COUNT + " 个生产者和 " + CONSUMER_COUNT + " 个消费者...");
for (int i = 0; i < PRODUCER_COUNT; i++) {
final int producerId = i + 1;
producerExecutor.submit(() -> {
for (int j = 0; j < ITEMS_PER_PRODUCER; j++) {
String item = "产品-" + producerId + "-" + (j + 1);
queue.putAsync(item).thenRun(() -> {
System.out.println("生产者 " + producerId + " 成功放入: " + item);
producedCount.incrementAndGet();
});
try {
Thread.sleep((long)(Math.random() * 100));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
}
for (int i = 0; i < CONSUMER_COUNT; i++) {
final int consumerId = i + 1;
consumerExecutor.submit(() -> {
while (consumedCount.get() < PRODUCER_COUNT * ITEMS_PER_PRODUCER) {
queue.takeAsync().thenAccept(item -> {
System.out.println("消费者 " + consumerId + " 成功取出: " + item);
consumedCount.incrementAndGet();
});
try {
Thread.sleep((long)(Math.random() * 200));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
}
producerExecutor.shutdown();
producerExecutor.awaitTermination(1, TimeUnit.MINUTES);
while (consumedCount.get() < PRODUCER_COUNT * ITEMS_PER_PRODUCER) {
Thread.sleep(100);
}
System.out.println("\n所有任务完成。");
System.out.println("总共生产: " + producedCount.get());
System.out.println("总共消费: " + consumedCount.get());
consumerExecutor.shutdownNow();
}
}
class AsyncQueue<T> {
private final BlockingQueue<T> queue;
private final ExecutorService executor = Executors.newCachedThreadPool();
public AsyncQueue(int capacity) {
this.queue = new ArrayBlockingQueue<>(capacity);
}
public CompletableFuture<Void> putAsync(T item) {
return CompletableFuture.runAsync(() -> {
try {
queue.put(item);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("放入队列时被中断", e);
}
}, executor);
}
public CompletableFuture<T> takeAsync() {
return CompletableFuture.supplyAsync(() -> {
try {
return queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("从队列取出时被中断", e);
}
}, executor);
}
public void shutdown() {
executor.shutdown();
}
}

View File

@@ -0,0 +1,47 @@
package multi_thread;
public class AlternatingPrint {
private final Object lock = new Object();
private int number = 1;
public static void main(String[] args) {
AlternatingPrint printer = new AlternatingPrint();
Thread oddThread = new Thread(printer::printOddNumbers, "奇数计数线程");
Thread evenThread = new Thread(printer::printEvenNumbers, "偶数计数线程");
oddThread.start();
evenThread.start();
}
public void printOddNumbers() {
synchronized (lock) {
while (number < 100) {
while (number % 2 == 0) {
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("奇数计数线程中断.");
}
}
System.out.println(Thread.currentThread().getName() + ": " + number);
number++;
lock.notifyAll();
}
}
}
public void printEvenNumbers() {
synchronized (lock) {
while (number <= 100) {
while (number % 2 != 0) {
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("偶数计数线程中断.");
}
}
System.out.println(Thread.currentThread().getName() + ": " + number);
number++;
lock.notifyAll();
}
}
}
}

View File

@@ -0,0 +1,43 @@
package multi_thread;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
int numberOfWorkers = 3;
CountDownLatch latch = new CountDownLatch(numberOfWorkers);
System.out.println("主线程启动工作线程...");
for (int i = 1; i <= numberOfWorkers; i++) {
Thread worker = new Thread(new Worker(i, latch));
worker.start();
}
System.out.println("主线程正在等待工作线程结束...");
latch.await();
System.out.println("所有工作线程结束,主线程继续运行。");
}
}
class Worker implements Runnable {
private final int id;
private final CountDownLatch latch;
public Worker(int id, CountDownLatch latch) {
this.id = id;
this.latch = latch;
}
@Override
public void run() {
try {
System.out.println("multi_thread.Worker " + id + " 开始工作。");
int workTime = (int) (Math.random() * 3000) + 1000;
TimeUnit.MILLISECONDS.sleep(workTime);
System.out.println("multi_thread.Worker " + id + " 完成工作。");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("multi_thread.Worker " + id + " 被中断。");
} finally {
latch.countDown();
System.out.println("multi_thread.Worker " + id + " 执行计数器减一. 剩余: " + latch.getCount());
}
}
}

View File

@@ -0,0 +1,55 @@
package multi_thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class ExecutorServiceDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<String>> futureList = new ArrayList<>();
int numberOfTasks = 5;
System.out.println("提交 " + numberOfTasks + " 个任务到线程池...");
for (int i = 1; i <= numberOfTasks; i++) {
Callable<String> task = new Task(i);
Future<String> future = executor.submit(task);
futureList.add(future);
}
System.out.println("所有任务已提交,获取结果...");
for (Future<String> future : futureList) {
try {
String result = future.get();
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
System.err.println("获取结果时出错 " + e.getMessage());
}
}
System.out.println("终止 executor service。");
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}
class Task implements Callable<String> {
private final int taskId;
public Task(int taskId) {
this.taskId = taskId;
}
@Override
public String call() throws Exception {
System.out.println("-> 任务 " + taskId + " 运行于线程: " + Thread.currentThread().getName());
TimeUnit.MILLISECONDS.sleep((long) (Math.random() * 2000) + 500);
return "任务结果: " + taskId;
}
}

View File

@@ -0,0 +1,74 @@
package multi_thread;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
public class ProducerConsumer {
public static void main(String[] args) {
Buffer buffer = new Buffer(5);
Thread producerThread = new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
buffer.produce(i);
Thread.sleep(new Random().nextInt(100));
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("生产者被中断。");
}
}, "生产者");
Thread consumerThread = new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
buffer.consume();
// 模拟消费耗时
Thread.sleep(new Random().nextInt(250));
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("消费者被中断。");
}
}, "消费者");
producerThread.start();
consumerThread.start();
try {
producerThread.join();
consumerThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("主线程在等待时被中断。");
}
System.out.println("所有生产和消费任务完成。程序结束。");
}
}
class Buffer {
private final Queue<Integer> queue;
private final int capacity;
public Buffer(int capacity) {
this.queue = new LinkedList<>();
this.capacity = capacity;
}
public synchronized void produce(int item) throws InterruptedException {
while (queue.size() == capacity) {
System.out.println("缓冲区已满。" + Thread.currentThread().getName() + " 进入等待状态 (释放锁)...");
wait();
System.out.println(Thread.currentThread().getName() + " 已被唤醒!");
}
queue.add(item);
System.out.println(Thread.currentThread().getName() + " 生产了: " + item + " (当前容量: " + queue.size() + ")");
notifyAll();
}
public synchronized int consume() throws InterruptedException {
while (queue.isEmpty()) {
System.out.println("缓冲区为空。" + Thread.currentThread().getName() + " 进入等待状态 (释放锁)...");
wait();
System.out.println(Thread.currentThread().getName() + " 已被唤醒!");
}
int item = queue.poll();
System.out.println(Thread.currentThread().getName() + " 消费了: " + item + " (当前容量: " + queue.size() + ")");
notifyAll();
return item;
}
}

View File

@@ -0,0 +1,26 @@
package multi_thread;
public class StaticSyncCounter {
private static int count = 0;
public static synchronized void increment() {
count++;
}
public static void main(String[] args) throws InterruptedException {
int numThreads = 10;
int incrementsPerThread = 1000;
Thread[] threads = new Thread[numThreads];
for (int i = 0; i < numThreads; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < incrementsPerThread; j++) {
increment();
}
});
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println("期望计数: " + (numThreads * incrementsPerThread));
System.out.println("实际计数: " + count);
}
}

View File

@@ -0,0 +1,87 @@
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Scanner;
public class NioChatClient {
private static final int PORT = 8080;
private static final String HOST = "127.0.0.1";
private static final Charset CHARSET = Charset.forName("UTF-8");
public static void main(String[] args) {
try {
Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_CONNECT);
socketChannel.connect(new InetSocketAddress(HOST, PORT));
new Thread(() -> {
try (Scanner scanner = new Scanner(System.in)) {
System.out.println("请输入要发送的消息...");
while (scanner.hasNextLine()) {
String message = scanner.nextLine();
if (message.length() > 0) {
socketChannel.write(CHARSET.encode(message));
}
}
} catch (IOException e) {
System.err.println("发送消息时发生错误: " + e.getMessage());
}
}).start();
while (true) {
if (selector.select() == 0) continue;
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isConnectable()) {
handleConnect(key, selector);
} else if (key.isReadable()) {
handleRead(key);
}
}
}
} catch (IOException e) {
System.err.println("客户端运行时发生错误: " + e.getMessage());
}
}
private static void handleConnect(SelectionKey key, Selector selector) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
if (channel.isConnectionPending()) {
channel.finishConnect();
}
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
System.out.println("成功连接到聊天服务器!");
}
private static void handleRead(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
StringBuilder content = new StringBuilder();
try {
int readBytes = channel.read(buffer);
if (readBytes > 0) {
buffer.flip();
content.append(CHARSET.decode(buffer));
System.out.println(content.toString());
} else if (readBytes == -1) {
System.out.println("服务器已关闭连接。");
key.cancel();
channel.close();
System.exit(0);
}
} catch (IOException e) {
System.out.println("读取服务器消息时出错,连接已断开。");
key.cancel();
channel.close();
System.exit(1);
}
}
}

View File

@@ -0,0 +1,109 @@
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.UUID;
public class NioChatServer {
private static final int PORT = 8080;
private static final String HOST = "127.0.0.1";
private static final Charset CHARSET = Charset.forName("UTF-8");
private static final ConcurrentHashMap<String, SocketChannel> clients = new ConcurrentHashMap<>();
public static void main(String[] args) {
try {
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(HOST, PORT));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("聊天服务器已启动,监听端口:" + PORT);
while (true) {
if (selector.select() == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isAcceptable()) {
handleAccept(key, selector);
} else if (key.isReadable()) {
handleRead(key);
}
}
}
} catch (IOException e) {
System.err.println("服务器运行时发生错误: " + e.getMessage());
}
}
private static void handleAccept(SelectionKey key, Selector selector) throws IOException {
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = serverChannel.accept();
clientChannel.configureBlocking(false);
SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ);
String clientId = UUID.randomUUID().toString();
clients.put(clientId, clientChannel);
clientKey.attach(clientId);
System.out.println("客户端 [" + clientChannel.getRemoteAddress() + "] 连接成功。");
broadcastMessage("系统消息:欢迎 " + clientChannel.getRemoteAddress() + " 加入聊天室!当前在线人数:" + clients.size());
}
private static void handleRead(SelectionKey key) {
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
StringBuilder content = new StringBuilder();
try {
int readBytes = clientChannel.read(buffer);
if (readBytes > 0) {
buffer.flip();
content.append(CHARSET.decode(buffer));
String receivedMessage = content.toString();
String address = clientChannel.getRemoteAddress().toString();
String broadcastMsg = "来自 " + address + " 的消息: " + receivedMessage;
System.out.println(broadcastMsg);
broadcastMessage(broadcastMsg, clientChannel);
} else if (readBytes == -1) {
disconnectClient(key);
}
} catch (IOException e) {
disconnectClient(key);
}
}
private static void broadcastMessage(String message) {
broadcastMessage(message, null);
}
private static void broadcastMessage(String message, SocketChannel excludeChannel) {
for (SocketChannel channel : clients.values()) {
if (channel.isOpen() && (excludeChannel == null || !channel.equals(excludeChannel))) {
try {
channel.write(CHARSET.encode(message));
} catch (IOException e) {
System.err.println("向客户端发送消息失败: " + e.getMessage());
}
}
}
}
private static void disconnectClient(SelectionKey key) {
String clientId = (String) key.attachment();
SocketChannel clientChannel = (SocketChannel) key.channel();
try {
String address = clientChannel.getRemoteAddress().toString();
key.cancel();
clientChannel.close();
if (clientId != null) {
clients.remove(clientId);
}
System.out.println("客户端 [" + address + "] 已断开连接。");
broadcastMessage("系统消息:" + address + " 离开了聊天室。当前在线人数:" + clients.size());
} catch (IOException e) {
System.err.println("关闭客户端连接时出错: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,84 @@
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;
public class NioHttpServer {
private static final int PORT = 8081;
private static final String HOST = "127.0.0.1";
public static void main(String[] args) {
try {
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(HOST, PORT));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("HTTP服务器已启动监听端口" + PORT);
while (true) {
if (selector.select(3000) == 0) {
continue;
}
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
if (key.isAcceptable()) {
handleAccept(key, selector);
}
if (key.isReadable()) {
handleRead(key);
}
}
}
} catch (IOException e) {
System.err.println("HTTP服务器运行时发生错误: " + e.getMessage());
}
}
private static void handleAccept(SelectionKey key, Selector selector) throws IOException {
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = serverChannel.accept();
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("接收到新的HTTP连接" + clientChannel.getRemoteAddress());
}
private static void handleRead(SelectionKey key) throws IOException {
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
int bytesRead = clientChannel.read(buffer);
if (bytesRead > 0) {
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String request = new String(bytes, StandardCharsets.UTF_8);
System.out.println("接收到HTTP请求:\n" + request);
String responseBody = "<h1>Hello NIO!</h1><p>这是一个基于Java NIO的HTTP服务器响应。</p>";
String httpResponse = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html; charset=utf-8\r\n" +
"Content-Length: " + responseBody.getBytes(StandardCharsets.UTF_8).length + "\r\n" +
"\r\n" +
responseBody;
ByteBuffer responseBuffer = ByteBuffer.wrap(httpResponse.getBytes(StandardCharsets.UTF_8));
clientChannel.write(responseBuffer);
}
} catch (IOException e) {
System.err.println("处理请求时发生错误: " + e.getMessage());
} finally {
if (clientChannel != null) {
clientChannel.close();
}
key.cancel();
}
}
}