commit 1f42e790611c70cf6597300ed43c7fa02c1d3eaf Author: Launchcore Date: Thu Nov 6 10:32:28 2025 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b618d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,204 @@ +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### MicrosoftOffice ### +*.tmp + +# Word temporary +~$*.doc* + +# Word Auto Backup File +Backup of *.doc* + +# Excel temporary +~$*.xls* + +# Excel Backup File +*.xlk + +# PowerPoint temporary +~$*.ppt* + +# Visio autosave temporary files +*.~vsd* + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk \ No newline at end of file diff --git a/Classwork/.gitignore b/Classwork/.gitignore new file mode 100644 index 0000000..f68d109 --- /dev/null +++ b/Classwork/.gitignore @@ -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 \ No newline at end of file diff --git a/Classwork/.idea/.gitignore b/Classwork/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/Classwork/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/Classwork/.idea/misc.xml b/Classwork/.idea/misc.xml new file mode 100644 index 0000000..5af9c98 --- /dev/null +++ b/Classwork/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Classwork/.idea/modules.xml b/Classwork/.idea/modules.xml new file mode 100644 index 0000000..630893a --- /dev/null +++ b/Classwork/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Classwork/.idea/vcs.xml b/Classwork/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/Classwork/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Classwork/Classwork.iml b/Classwork/Classwork.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/Classwork/Classwork.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Classwork/src/Bank/Bank.java b/Classwork/src/Bank/Bank.java new file mode 100644 index 0000000..30d8b1b --- /dev/null +++ b/Classwork/src/Bank/Bank.java @@ -0,0 +1,40 @@ +package Bank; + +public class Bank { + private int money; + private String name; + + public Bank(String name, int money) { + this.name = name; + this.money = money; + } + + public synchronized void deposit(int m) { + money += m; + } + + public synchronized boolean withdraw(int m) { + if (money >= m) { + money -= m; + check(); + return true; + } else { + return false; + } + } + + public String getName() { + return name; + } + + private void check() { + if (money < 0) { + System.out.println("可用余额为负数,money=" + money); + } + /* + else { + System.out.println("money=" + money); + } + */ + } +} diff --git a/Classwork/src/Bank/ClientThread.java b/Classwork/src/Bank/ClientThread.java new file mode 100644 index 0000000..49c07c5 --- /dev/null +++ b/Classwork/src/Bank/ClientThread.java @@ -0,0 +1,17 @@ +package Bank; + +public class ClientThread extends Thread{ + private Bank bank; + public ClientThread(Bank bank) { + this.bank = bank; + } + @Override + public void run(){ + while (true){ + boolean ok=bank.withdraw(1000); + if(ok){ + bank.deposit(1000); + } + } + } +} \ No newline at end of file diff --git a/Classwork/src/Bank/MainTest.java b/Classwork/src/Bank/MainTest.java new file mode 100644 index 0000000..10c7f4a --- /dev/null +++ b/Classwork/src/Bank/MainTest.java @@ -0,0 +1,15 @@ +package Bank; + +public class MainTest { + public static void main(String[] args) { + Bank bank = new Bank("a bad bank", 1000); + new ClientThread(bank).start(); + new ClientThread(bank).start(); + new ClientThread(bank).start(); + new ClientThread(bank).start(); + new ClientThread(bank).start(); + new ClientThread(bank).start(); + new ClientThread(bank).start(); + new ClientThread(bank).start(); + } +} \ No newline at end of file diff --git a/Classwork/src/Buffer/BufferCreateIO.java b/Classwork/src/Buffer/BufferCreateIO.java new file mode 100644 index 0000000..d1dc160 --- /dev/null +++ b/Classwork/src/Buffer/BufferCreateIO.java @@ -0,0 +1,45 @@ +package Buffer; + +import java.nio.ByteBuffer; + +import static Buffer.BufferOperation.bufferToString; + +public class BufferCreateIO { + public static void main(String[] args) { + ByteBuffer buffer = ByteBuffer.allocate(10); + System.out.println("初始状态: " + bufferToString(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("写入5个字节后: " + bufferToString(buffer)); + + // 切换为读模式 + buffer.flip(); + System.out.println("调用flip()后 (读模式): " + bufferToString(buffer)); + + // 读取并打印所有数据 + System.out.print("读取数据: "); + while (buffer.hasRemaining()) { + System.out.print(buffer.get() + " "); + } + System.out.println("\n读取完毕后: " + bufferToString(buffer)); + + // 清空缓冲区 + buffer.clear(); + System.out.println("调用clear()后: " + bufferToString(buffer)); + + // 验证是否可重新写入 + buffer.put((byte) 6); + System.out.println("重新写入一个字节 (6) 后: " + bufferToString(buffer)); + buffer.flip(); + System.out.print("读取新写入的数据: "); + while (buffer.hasRemaining()) { + System.out.print(buffer.get() + " "); + } + System.out.println(); + } +} diff --git a/Classwork/src/Buffer/BufferOperation.java b/Classwork/src/Buffer/BufferOperation.java new file mode 100644 index 0000000..a3657d1 --- /dev/null +++ b/Classwork/src/Buffer/BufferOperation.java @@ -0,0 +1,24 @@ +package Buffer; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.IntBuffer; + +public class BufferOperation { + public static String bufferToString(ByteBuffer buffer) { + return "pos=" + buffer.position() + " lim=" + buffer.limit() + " cap=" + buffer.capacity(); + } + public static String charBufferToString(CharBuffer buffer) { + return "pos=" + buffer.position() + " lim=" + buffer.limit() + " cap=" + buffer.capacity(); + } + public static String intBufferToString(IntBuffer buffer) { + return "pos=" + buffer.position() + " lim=" + buffer.limit() + " cap=" + buffer.capacity(); + } + public static String bytesToHex(byte[] bytes, int length) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + sb.append(String.format("%02X ", bytes[i])); + } + return sb.toString().trim(); + } +} diff --git a/Classwork/src/Data/Data.java b/Classwork/src/Data/Data.java new file mode 100644 index 0000000..51d1471 --- /dev/null +++ b/Classwork/src/Data/Data.java @@ -0,0 +1,56 @@ +package Data; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class Data { + private final char[] buffer; + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + private final Lock readLock = rwLock.readLock(); + private final Lock writeLock = rwLock.writeLock(); + + public Data(int size) { + this.buffer = new char[size]; + for (int i = 0; i < buffer.length; i++) { + buffer[i] = '*'; + } + } + + public char[] read() throws InterruptedException { + readLock.lock(); + try { + return doRead(); + } finally { + readLock.unlock(); + } + } + + public void write(char c) throws InterruptedException { + writeLock.lock(); + try { + doWrite(c); + } finally { + writeLock.unlock(); + } + } + + private char[] doRead() throws InterruptedException { + char[] newbuf = new char[buffer.length]; + for (int i = 0; i < buffer.length; i++) { + newbuf[i] = buffer[i]; + } + slowly(); + return newbuf; + } + + private void doWrite(char c) throws InterruptedException { + for (int i = 0; i < buffer.length; i++) { + buffer[i] = c; + slowly(); + } + } + + private void slowly() throws InterruptedException { + Thread.sleep(50); + } +} \ No newline at end of file diff --git a/Classwork/src/Data/Main.java b/Classwork/src/Data/Main.java new file mode 100644 index 0000000..93b840d --- /dev/null +++ b/Classwork/src/Data/Main.java @@ -0,0 +1,40 @@ +package Data; + +public class Main { + public static void main(String[] args) { + Data data = new Data(10); + + ReaderThread reader1 = new ReaderThread("Reader-1", data); + ReaderThread reader2 = new ReaderThread("Reader-2", data); + ReaderThread reader3 = new ReaderThread("Reader-3", data); + ReaderThread reader4 = new ReaderThread("Reader-4", data); + + WriterThread writer1 = new WriterThread("Writer-A", data, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + WriterThread writer2 = new WriterThread("Writer-B", data, "abcdefghijklmnopqrstuvwxyz"); + + System.out.println("Starting threads..."); + + reader1.start(); + reader2.start(); + writer1.start(); + reader3.start(); + reader4.start(); + writer2.start(); + + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + System.out.println("\nInterrupting threads..."); + reader1.interrupt(); + reader2.interrupt(); + reader3.interrupt(); + reader4.interrupt(); + writer1.interrupt(); + writer2.interrupt(); + + System.out.println("Main thread finished."); + } +} \ No newline at end of file diff --git a/Classwork/src/Data/ReaderThread.java b/Classwork/src/Data/ReaderThread.java new file mode 100644 index 0000000..60d27cd --- /dev/null +++ b/Classwork/src/Data/ReaderThread.java @@ -0,0 +1,24 @@ +package Data; + +public class ReaderThread extends Thread { + private final Data data; + + public ReaderThread(String name, Data data) { + super(name); + this.data = data; + } + + @Override + public void run() { + try { + while (true) { + char[] readBuf = data.read(); + System.out.println(Thread.currentThread().getName() + " reads " + String.valueOf(readBuf)); + Thread.sleep(100); + } + } catch (InterruptedException e) { + System.out.println(Thread.currentThread().getName() + " was interrupted."); + Thread.currentThread().interrupt(); + } + } +} \ No newline at end of file diff --git a/Classwork/src/Data/WriterThread.java b/Classwork/src/Data/WriterThread.java new file mode 100644 index 0000000..91cb436 --- /dev/null +++ b/Classwork/src/Data/WriterThread.java @@ -0,0 +1,37 @@ +package Data; + +public class WriterThread extends Thread { + private final Data data; + private final String filler; + private int index = 0; + + public WriterThread(String name, Data data, String filler) { + super(name); + this.data = data; + this.filler = filler; + } + + @Override + public void run() { + try { + while (true) { + char c = nextChar(); + data.write(c); + System.out.println(Thread.currentThread().getName() + " writes " + c); + Thread.sleep(300); + } + } catch (InterruptedException e) { + System.out.println(Thread.currentThread().getName() + " was interrupted."); + Thread.currentThread().interrupt(); + } + } + + private char nextChar() { + char c = filler.charAt(index); + index++; + if (index >= filler.length()) { + index = 0; + } + return c; + } +} \ No newline at end of file diff --git a/Classwork/src/DataLimited/Data.java b/Classwork/src/DataLimited/Data.java new file mode 100644 index 0000000..70a4874 --- /dev/null +++ b/Classwork/src/DataLimited/Data.java @@ -0,0 +1,63 @@ +package DataLimited; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class Data { + private final char[] buffer; + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + private final Lock readLock = rwLock.readLock(); + private final Lock writeLock = rwLock.writeLock(); + private final Semaphore readSemaphore = new Semaphore(3); + + public Data(int size) { + this.buffer = new char[size]; + for (int i = 0; i < buffer.length; i++) { + buffer[i] = '*'; + } + } + + public char[] read() throws InterruptedException { + readSemaphore.acquire(); + try { + readLock.lock(); + try { + return doRead(); + } finally { + readLock.unlock(); + } + } finally { + readSemaphore.release(); + } + } + + public void write(char c) throws InterruptedException { + writeLock.lock(); + try { + doWrite(c); + } finally { + writeLock.unlock(); + } + } + + private char[] doRead() throws InterruptedException { + char[] newbuf = new char[buffer.length]; + for (int i = 0; i < buffer.length; i++) { + newbuf[i] = buffer[i]; + } + slowly(); + return newbuf; + } + + private void doWrite(char c) throws InterruptedException { + for (int i = 0; i < buffer.length; i++) { + buffer[i] = c; + slowly(); + } + } + + private void slowly() throws InterruptedException { + Thread.sleep(50); + } +} \ No newline at end of file diff --git a/Classwork/src/DataLimited/Main.java b/Classwork/src/DataLimited/Main.java new file mode 100644 index 0000000..be4db07 --- /dev/null +++ b/Classwork/src/DataLimited/Main.java @@ -0,0 +1,40 @@ +package DataLimited; + +public class Main { + public static void main(String[] args) { + Data data = new Data(10); + + ReaderThread reader1 = new ReaderThread("Reader-1", data); + ReaderThread reader2 = new ReaderThread("Reader-2", data); + ReaderThread reader3 = new ReaderThread("Reader-3", data); + ReaderThread reader4 = new ReaderThread("Reader-4", data); + + WriterThread writer1 = new WriterThread("Writer-A", data, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + WriterThread writer2 = new WriterThread("Writer-B", data, "abcdefghijklmnopqrstuvwxyz"); + + System.out.println("Starting threads..."); + + reader1.start(); + reader2.start(); + writer1.start(); + reader3.start(); + reader4.start(); + writer2.start(); + + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + System.out.println("\nInterrupting threads..."); + reader1.interrupt(); + reader2.interrupt(); + reader3.interrupt(); + reader4.interrupt(); + writer1.interrupt(); + writer2.interrupt(); + + System.out.println("Main thread finished."); + } +} \ No newline at end of file diff --git a/Classwork/src/DataLimited/ReaderThread.java b/Classwork/src/DataLimited/ReaderThread.java new file mode 100644 index 0000000..e409280 --- /dev/null +++ b/Classwork/src/DataLimited/ReaderThread.java @@ -0,0 +1,24 @@ +package DataLimited; + +public class ReaderThread extends Thread { + private final Data data; + + public ReaderThread(String name, Data data) { + super(name); + this.data = data; + } + + @Override + public void run() { + try { + while (true) { + char[] readBuf = data.read(); + System.out.println(Thread.currentThread().getName() + " reads " + String.valueOf(readBuf)); + Thread.sleep(100); + } + } catch (InterruptedException e) { + System.out.println(Thread.currentThread().getName() + " was interrupted."); + Thread.currentThread().interrupt(); + } + } +} \ No newline at end of file diff --git a/Classwork/src/DataLimited/WriterThread.java b/Classwork/src/DataLimited/WriterThread.java new file mode 100644 index 0000000..87bd390 --- /dev/null +++ b/Classwork/src/DataLimited/WriterThread.java @@ -0,0 +1,37 @@ +package DataLimited; + +public class WriterThread extends Thread { + private final Data data; + private final String filler; + private int index = 0; + + public WriterThread(String name, Data data, String filler) { + super(name); + this.data = data; + this.filler = filler; + } + + @Override + public void run() { + try { + while (true) { + char c = nextChar(); + data.write(c); + System.out.println(Thread.currentThread().getName() + " writes " + c); + Thread.sleep(300); + } + } catch (InterruptedException e) { + System.out.println(Thread.currentThread().getName() + " was interrupted."); + Thread.currentThread().interrupt(); + } + } + + private char nextChar() { + char c = filler.charAt(index); + index++; + if (index >= filler.length()) { + index = 0; + } + return c; + } +} \ No newline at end of file diff --git a/Classwork/src/ProducerConsumer/extthread/ThreadC.java b/Classwork/src/ProducerConsumer/extthread/ThreadC.java new file mode 100644 index 0000000..6f641d2 --- /dev/null +++ b/Classwork/src/ProducerConsumer/extthread/ThreadC.java @@ -0,0 +1,19 @@ +package ProducerConsumer.extthread; + +import ProducerConsumer.service.RepastService; + +public class ThreadC extends Thread { + + private RepastService service; + + public ThreadC(RepastService service) { + super(); + this.service = service; + } + + @Override + public void run() { + service.get(); + } + +} diff --git a/Classwork/src/ProducerConsumer/extthread/ThreadP.java b/Classwork/src/ProducerConsumer/extthread/ThreadP.java new file mode 100644 index 0000000..267f9be --- /dev/null +++ b/Classwork/src/ProducerConsumer/extthread/ThreadP.java @@ -0,0 +1,19 @@ +package ProducerConsumer.extthread; + +import ProducerConsumer.service.RepastService; + +public class ThreadP extends Thread { + + private RepastService service; + + public ThreadP(RepastService service) { + super(); + this.service = service; + } + + @Override + public void run() { + service.set(); + } + +} diff --git a/Classwork/src/ProducerConsumer/service/RepastService.java b/Classwork/src/ProducerConsumer/service/RepastService.java new file mode 100644 index 0000000..5939cfa --- /dev/null +++ b/Classwork/src/ProducerConsumer/service/RepastService.java @@ -0,0 +1,94 @@ +package ProducerConsumer.service; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +public class RepastService { + + volatile private Semaphore setSemaphore = new Semaphore(10);// 厨师 + volatile private Semaphore getSemaphore = new Semaphore(20);// 就餐者 + volatile private ReentrantLock lock = new ReentrantLock(); + volatile private Condition setCondition = lock.newCondition(); + volatile private Condition getCondition = lock.newCondition(); + volatile private Object[] producePosition = new Object[4]; + + private boolean isEmpty() { + boolean isEmpty = true; + for (int i = 0; i < producePosition.length; i++) { + if (producePosition[i] != null) { + isEmpty = false; + break; + } + } + if (isEmpty == true) { + return true; + } else { + return false; + } + } + + private boolean isFull() { + boolean isFull = true; + for (int i = 0; i < producePosition.length; i++) { + if (producePosition[i] == null) { + isFull = false; + break; + } + } + return isFull; + } + + public void set() { + try { + // System.out.println("set"); + setSemaphore.acquire();// 允许同时最多有10个厨师进行生产 + lock.lock(); + while (isFull()) { + System.out.println("生产者在等待"); + setCondition.await(); + } + for (int i = 0; i < producePosition.length; i++) { + if (producePosition[i] == null) { + producePosition[i] = "数据"; + System.out.println(Thread.currentThread().getName() + + " 生产了 " + producePosition[i]); + break; + } + } + getCondition.signalAll(); + lock.unlock(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + setSemaphore.release(); + } + } + + public void get() { + try { + // System.out.println("get"); + getSemaphore.acquire();// 允许同时最多有16个就餐者 + lock.lock(); + while (isEmpty()) { + System.out.println("消费者在等待"); + getCondition.await(); + } + for (int i = 0; i < producePosition.length; i++) { + if (producePosition[i] != null) { + System.out.println(Thread.currentThread().getName() + + " 消费了 " + producePosition[i]); + producePosition[i] = null; + break; + } + } + setCondition.signalAll(); + lock.unlock(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + getSemaphore.release(); + } + } + +} diff --git a/Classwork/src/ProducerConsumer/test/run/Run.java b/Classwork/src/ProducerConsumer/test/run/Run.java new file mode 100644 index 0000000..362b771 --- /dev/null +++ b/Classwork/src/ProducerConsumer/test/run/Run.java @@ -0,0 +1,24 @@ +package ProducerConsumer.test.run; + +import ProducerConsumer.service.RepastService; +import ProducerConsumer.extthread.ThreadC; +import ProducerConsumer.extthread.ThreadP; + +public class Run { + + public static void main(String[] args) throws InterruptedException { + RepastService service = new RepastService(); + ThreadP[] arrayP = new ThreadP[60]; + ThreadC[] arrayC = new ThreadC[60]; + for (int i = 0; i < 60; i++) { + arrayP[i] = new ThreadP(service); + arrayC[i] = new ThreadC(service); + } + Thread.sleep(2000); + for (int i = 0; i < 60; i++) { + arrayP[i].start(); + arrayC[i].start(); + } + } + +} diff --git a/Classwork/src/Race/TortoiseHareRace.java b/Classwork/src/Race/TortoiseHareRace.java new file mode 100644 index 0000000..21ebab1 --- /dev/null +++ b/Classwork/src/Race/TortoiseHareRace.java @@ -0,0 +1,88 @@ +package Race; + +import java.util.Random; +import java.util.concurrent.TimeUnit; + +public class TortoiseHareRace { + private static final int RACE_LENGTH = 100; // 赛道长度(米) + private static int tortoisePosition = 0; // 乌龟位置 + private static int harePosition = 0; // 兔子位置 + private static boolean raceFinished = false; // 比赛是否结束 + private static final Object lock = new Object(); // 同步锁 + + public static void main(String[] args) { + Random random = new Random(); + + // 乌龟线程:速度慢但稳定 + Thread tortoise = new Thread(() -> { + while (!raceFinished) { + synchronized (lock) { + // 乌龟每次移动1-2米 + int step = random.nextInt(2) + 1; + tortoisePosition += step; + System.out.println("乌龟前进了" + step + "米,当前位置:" + tortoisePosition + "米"); + + if (tortoisePosition >= RACE_LENGTH) { + raceFinished = true; + System.out.println("乌龟赢得了比赛!"); + } + } + + try { + TimeUnit.MILLISECONDS.sleep(200); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }, "乌龟"); + + // 兔子线程:速度快但会休息 + Thread hare = new Thread(() -> { + while (!raceFinished) { + synchronized (lock) { + // 兔子移动速度更快,每次移动5-10米 + int step = random.nextInt(6) + 5; + harePosition += step; + System.out.println("兔子前进了" + step + "米,当前位置:" + harePosition + "米"); + + if (harePosition >= RACE_LENGTH) { + raceFinished = true; + System.out.println("兔子赢得了比赛!"); + } + } + + // 兔子有30%的概率会休息 + if (random.nextInt(10) < 3) { + int restTime = random.nextInt(600) + 200; + System.out.println("兔子太自信了,休息" + restTime + "毫秒"); + try { + TimeUnit.MILLISECONDS.sleep(restTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } else { + try { + TimeUnit.MILLISECONDS.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }, "兔子"); + + System.out.println("比赛开始!"); + tortoise.start(); + hare.start(); + + try { + tortoise.join(); + hare.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println("比赛结束!"); + System.out.println("最终结果 - 乌龟:" + Math.min(tortoisePosition, RACE_LENGTH) + + "米,兔子:" + Math.min(harePosition, RACE_LENGTH) + "米"); + } +} \ No newline at end of file diff --git a/Classwork/src/RedPacket/AICRedPacketGrabber.java b/Classwork/src/RedPacket/AICRedPacketGrabber.java new file mode 100644 index 0000000..b1549e2 --- /dev/null +++ b/Classwork/src/RedPacket/AICRedPacketGrabber.java @@ -0,0 +1,78 @@ +package RedPacket; + +import java.util.Random; + +public class AICRedPacketGrabber { + private static int totalMoney = 100; + private static int thread1Money = 0; + private static int thread2Money = 0; + private static final Object lock = new Object(); + + public static void main(String[] args) { + Thread thread1 = new Thread(new Runnable() { + @Override + public void run() { + grabMoney(true); + } + }, "线程1"); + + Thread thread2 = new Thread(new Runnable() { + @Override + public void run() { + grabMoney(false); + } + }, "线程2"); + + thread1.start(); + thread2.start(); + + try { + thread1.join(); + thread2.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println("线程1抢到的总金额: " + thread1Money + "元"); + System.out.println("线程2抢到的总金额: " + thread2Money + "元"); + System.out.println("剩余金额: " + totalMoney + "元"); + } + + private static void grabMoney(boolean isThread1) { + Random random = new Random(); + + while (true) { + synchronized (lock) { + if (totalMoney < 1) { + break; + } + + int grabMoney = random.nextInt(3) + 1; + + if (grabMoney > totalMoney) { + grabMoney = totalMoney; + } + + totalMoney -= grabMoney; + + if (isThread1) { + thread1Money += grabMoney; + System.out.println("线程1抢到了" + grabMoney + "元,剩余" + totalMoney + "元"); + } else { + thread2Money += grabMoney; + System.out.println("线程2抢到了" + grabMoney + "元,剩余" + totalMoney + "元"); + } + + if (totalMoney == 0) { + break; + } + } + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/Classwork/src/RedPacket/CFRedPacketGrabber.java b/Classwork/src/RedPacket/CFRedPacketGrabber.java new file mode 100644 index 0000000..2db58e8 --- /dev/null +++ b/Classwork/src/RedPacket/CFRedPacketGrabber.java @@ -0,0 +1,91 @@ +package RedPacket; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.Scanner; +import java.util.concurrent.*; + +public class CFRedPacketGrabber { + private static int totalMoney = 100; + private static final Object lock = new Object(); + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + System.out.print("请输入参与抢红包的线程数: "); + int threadCount = scanner.nextInt(); + scanner.close(); + + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + List> futures = new ArrayList<>(); + + for (int i = 0; i < threadCount; i++) { + final int threadId = i + 1; + Future future = executor.submit(new RedPacketGrabber(threadId)); + futures.add(future); + } + + int[] threadMoney = new int[threadCount]; + try { + for (int i = 0; i < threadCount; i++) { + threadMoney[i] = futures.get(i).get(); + } + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + + executor.shutdown(); + + for (int i = 0; i < threadCount; i++) { + System.out.println("线程" + (i + 1) + "抢到的总金额: " + threadMoney[i] + "元"); + } + System.out.println("剩余金额: " + totalMoney + "元"); + } + + static class RedPacketGrabber implements Callable { + private final int threadId; + private int moneyGrabbed = 0; + + public RedPacketGrabber(int threadId) { + this.threadId = threadId; + } + + @Override + public Integer call() { + Random random = new Random(); + String threadName = "线程" + threadId; + + while (true) { + synchronized (lock) { + if (totalMoney < 1) { + break; + } + + int grabMoney = random.nextInt(3) + 1; + + if (grabMoney > totalMoney) { + grabMoney = totalMoney; + } + + totalMoney -= grabMoney; + moneyGrabbed += grabMoney; + + System.out.println(threadName + "抢到了" + grabMoney + "元,剩余" + totalMoney + "元"); + + if (totalMoney == 0) { + break; + } + } + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + + return moneyGrabbed; + } + } +} diff --git a/Classwork/src/RedPacket/LambdaRedPacketGrabber.java b/Classwork/src/RedPacket/LambdaRedPacketGrabber.java new file mode 100644 index 0000000..53a0b20 --- /dev/null +++ b/Classwork/src/RedPacket/LambdaRedPacketGrabber.java @@ -0,0 +1,82 @@ +package RedPacket; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.Scanner; +import java.util.concurrent.*; + +public class LambdaRedPacketGrabber { + private static int totalMoney = 100; + private static final Object lock = new Object(); + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + System.out.print("请输入参与抢红包的线程数: "); + int threadCount = scanner.nextInt(); + scanner.close(); + + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + List> futures = new ArrayList<>(); + + for (int i = 0; i < threadCount; i++) { + final int threadId = i + 1; + + Future future = executor.submit(() -> { + Random random = new Random(); + String threadName = "线程" + threadId; + int moneyGrabbed = 0; + + while (true) { + synchronized (lock) { + if (totalMoney < 1) { + break; + } + + int grabMoney = random.nextInt(3) + 1; + + if (grabMoney > totalMoney) { + grabMoney = totalMoney; + } + + totalMoney -= grabMoney; + moneyGrabbed += grabMoney; + + System.out.println(threadName + "抢到了" + grabMoney + "元,剩余" + totalMoney + "元"); + + if (totalMoney == 0) { + break; + } + } + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + + return moneyGrabbed; + }); + + futures.add(future); + } + + int[] threadMoney = new int[threadCount]; + try { + for (int i = 0; i < threadCount; i++) { + threadMoney[i] = futures.get(i).get(); + } + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + + executor.shutdown(); + + for (int i = 0; i < threadCount; i++) { + System.out.println("线程" + (i + 1) + "抢到的总金额: " + threadMoney[i] + "元"); + } + System.out.println("剩余金额: " + totalMoney + "元"); + } +} diff --git a/Classwork/src/RedPacket/OrderedRedPacketGrabber.java b/Classwork/src/RedPacket/OrderedRedPacketGrabber.java new file mode 100644 index 0000000..430c7ea --- /dev/null +++ b/Classwork/src/RedPacket/OrderedRedPacketGrabber.java @@ -0,0 +1,76 @@ +package RedPacket; + +import java.util.Random; + +public class OrderedRedPacketGrabber { + private static int totalMoney = 100; + private static int thread1Money = 0; + private static int thread2Money = 0; + private static boolean isThread1Turn = true; + private static final Object lock = new Object(); + + public static void main(String[] args) { + Thread thread1 = new Thread(() -> grabMoney(true), "线程1"); + Thread thread2 = new Thread(() -> grabMoney(false), "线程2"); + + thread1.start(); + thread2.start(); + + try { + thread1.join(); + thread2.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println("线程1抢到的总金额: " + thread1Money + "元"); + System.out.println("线程2抢到的总金额: " + thread2Money + "元"); + System.out.println("剩余金额: " + totalMoney + "元"); + } + + private static void grabMoney(boolean isThread1) { + Random random = new Random(); + + while (true) { + synchronized (lock) { + while (isThread1Turn != isThread1 && totalMoney >= 1) { + try { + lock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + if (totalMoney < 1) { + lock.notifyAll(); + break; + } + + int grabMoney = random.nextInt(3) + 1; + + if (grabMoney > totalMoney) { + grabMoney = totalMoney; + } + + totalMoney -= grabMoney; + + if (isThread1) { + thread1Money += grabMoney; + System.out.println("线程1抢到了" + grabMoney + "元,剩余" + totalMoney + "元"); + } else { + thread2Money += grabMoney; + System.out.println("线程2抢到了" + grabMoney + "元,剩余" + totalMoney + "元"); + } + + isThread1Turn = !isThread1Turn; + + lock.notify(); + + if (totalMoney == 0) { + lock.notifyAll(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Classwork/src/RedPacket/RandomRedPacketGrabber.java b/Classwork/src/RedPacket/RandomRedPacketGrabber.java new file mode 100644 index 0000000..0c752a4 --- /dev/null +++ b/Classwork/src/RedPacket/RandomRedPacketGrabber.java @@ -0,0 +1,67 @@ +package RedPacket; + +import java.util.Random; + +public class RandomRedPacketGrabber { + private static int totalMoney = 100; + private static int thread1Money = 0; + private static int thread2Money = 0; + private static final Object lock = new Object(); + + public static void main(String[] args) { + Thread thread1 = new Thread(() -> grabMoney(true), "线程1"); + Thread thread2 = new Thread(() -> grabMoney(false), "线程2"); + + thread1.start(); + thread2.start(); + + try { + thread1.join(); + thread2.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println("线程1抢到的总金额: " + thread1Money + "元"); + System.out.println("线程2抢到的总金额: " + thread2Money + "元"); + System.out.println("剩余金额: " + totalMoney + "元"); + } + + private static void grabMoney(boolean isThread1) { + Random random = new Random(); + + while (true) { + synchronized (lock) { + if (totalMoney < 1) { + break; + } + + int grabMoney = random.nextInt(3) + 1; + + if (grabMoney > totalMoney) { + grabMoney = totalMoney; + } + + totalMoney -= grabMoney; + + if (isThread1) { + thread1Money += grabMoney; + System.out.println("线程1抢到了" + grabMoney + "元,剩余" + totalMoney + "元"); + } else { + thread2Money += grabMoney; + System.out.println("线程2抢到了" + grabMoney + "元,剩余" + totalMoney + "元"); + } + + if (totalMoney == 0) { + break; + } + } + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} \ No newline at end of file diff --git a/Classwork/src/RedPacket/ThreadPoolRedPacketGrabber.java b/Classwork/src/RedPacket/ThreadPoolRedPacketGrabber.java new file mode 100644 index 0000000..019ff62 --- /dev/null +++ b/Classwork/src/RedPacket/ThreadPoolRedPacketGrabber.java @@ -0,0 +1,88 @@ +package RedPacket; + +import java.util.Random; +import java.util.concurrent.*; + +public class ThreadPoolRedPacketGrabber { + private static int totalMoney = 100; + private static final int THREAD_COUNT = 2; + private static final Object lock = new Object(); + + public static void main(String[] args) { + ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT); + + CountDownLatch latch = new CountDownLatch(THREAD_COUNT); + + int[] threadMoney = new int[THREAD_COUNT]; + + for (int i = 0; i < THREAD_COUNT; i++) { + final int threadId = i; + executor.submit(new RedPacketGrabber(threadId, threadMoney, latch)); + } + + try { + latch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + executor.shutdown(); + + for (int i = 0; i < THREAD_COUNT; i++) { + System.out.println("线程" + (i + 1) + "抢到的总金额: " + threadMoney[i] + "元"); + } + System.out.println("剩余金额: " + totalMoney + "元"); + } + + static class RedPacketGrabber implements Runnable { + private final int threadId; + private final int[] threadMoney; + private final CountDownLatch latch; + + public RedPacketGrabber(int threadId, int[] threadMoney, CountDownLatch latch) { + this.threadId = threadId; + this.threadMoney = threadMoney; + this.latch = latch; + } + + @Override + public void run() { + try { + Random random = new Random(); + String threadName = "线程" + (threadId + 1); + + while (true) { + synchronized (lock) { + if (totalMoney < 1) { + break; + } + + int grabMoney = random.nextInt(3) + 1; + + if (grabMoney > totalMoney) { + grabMoney = totalMoney; + } + + totalMoney -= grabMoney; + threadMoney[threadId] += grabMoney; + + System.out.println(threadName + "抢到了" + grabMoney + "元,剩余" + totalMoney + "元"); + + if (totalMoney == 0) { + break; + } + } + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + } finally { + latch.countDown(); + } + } + } +} \ No newline at end of file diff --git a/Final/.gitignore b/Final/.gitignore new file mode 100644 index 0000000..f68d109 --- /dev/null +++ b/Final/.gitignore @@ -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 \ No newline at end of file diff --git a/Final/.idea/.gitignore b/Final/.idea/.gitignore new file mode 100644 index 0000000..7d05e99 --- /dev/null +++ b/Final/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# 依赖于环境的 Maven 主目录路径 +/mavenHomeManager.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/Final/.idea/misc.xml b/Final/.idea/misc.xml new file mode 100644 index 0000000..6f29fee --- /dev/null +++ b/Final/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Final/.idea/modules.xml b/Final/.idea/modules.xml new file mode 100644 index 0000000..cb7a089 --- /dev/null +++ b/Final/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Final/.idea/uiDesigner.xml b/Final/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/Final/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Final/.idea/vcs.xml b/Final/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/Final/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Final/Final.iml b/Final/Final.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/Final/Final.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Final/src/aio/AIOChatClient.java b/Final/src/aio/AIOChatClient.java new file mode 100644 index 0000000..37dc0c6 --- /dev/null +++ b/Final/src/aio/AIOChatClient.java @@ -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() { + @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() { + @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() { + @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(); + } + } +} diff --git a/Final/src/aio/AIOChatServer.java b/Final/src/aio/AIOChatServer.java new file mode 100644 index 0000000..f9572b7 --- /dev/null +++ b/Final/src/aio/AIOChatServer.java @@ -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 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 { + @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 { + @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() { + @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(); + } +} \ No newline at end of file diff --git a/Final/src/aio/AsyncQueueDemo.java b/Final/src/aio/AsyncQueueDemo.java new file mode 100644 index 0000000..b142631 --- /dev/null +++ b/Final/src/aio/AsyncQueueDemo.java @@ -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 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 { + private final BlockingQueue queue; + private final ExecutorService executor = Executors.newCachedThreadPool(); + public AsyncQueue(int capacity) { + this.queue = new ArrayBlockingQueue<>(capacity); + } + public CompletableFuture putAsync(T item) { + return CompletableFuture.runAsync(() -> { + try { + queue.put(item); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("放入队列时被中断", e); + } + }, executor); + } + public CompletableFuture takeAsync() { + return CompletableFuture.supplyAsync(() -> { + try { + return queue.take(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("从队列取出时被中断", e); + } + }, executor); + } + public void shutdown() { + executor.shutdown(); + } +} diff --git a/Final/src/multi_thread/AlternatingPrint.java b/Final/src/multi_thread/AlternatingPrint.java new file mode 100644 index 0000000..a077647 --- /dev/null +++ b/Final/src/multi_thread/AlternatingPrint.java @@ -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(); + } + } + } +} \ No newline at end of file diff --git a/Final/src/multi_thread/CountDownLatchDemo.java b/Final/src/multi_thread/CountDownLatchDemo.java new file mode 100644 index 0000000..6cab73f --- /dev/null +++ b/Final/src/multi_thread/CountDownLatchDemo.java @@ -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()); + } + } +} diff --git a/Final/src/multi_thread/ExecutorServiceDemo.java b/Final/src/multi_thread/ExecutorServiceDemo.java new file mode 100644 index 0000000..441a8b1 --- /dev/null +++ b/Final/src/multi_thread/ExecutorServiceDemo.java @@ -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> futureList = new ArrayList<>(); + int numberOfTasks = 5; + System.out.println("提交 " + numberOfTasks + " 个任务到线程池..."); + for (int i = 1; i <= numberOfTasks; i++) { + Callable task = new Task(i); + Future future = executor.submit(task); + futureList.add(future); + } + System.out.println("所有任务已提交,获取结果..."); + for (Future 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 { + 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; + } +} diff --git a/Final/src/multi_thread/ProducerConsumer.java b/Final/src/multi_thread/ProducerConsumer.java new file mode 100644 index 0000000..b51fc35 --- /dev/null +++ b/Final/src/multi_thread/ProducerConsumer.java @@ -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 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; + } +} diff --git a/Final/src/multi_thread/StaticSyncCounter.java b/Final/src/multi_thread/StaticSyncCounter.java new file mode 100644 index 0000000..fa9ccfb --- /dev/null +++ b/Final/src/multi_thread/StaticSyncCounter.java @@ -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); + } +} \ No newline at end of file diff --git a/Final/src/nio/NioChatClient.java b/Final/src/nio/NioChatClient.java new file mode 100644 index 0000000..f5c87fd --- /dev/null +++ b/Final/src/nio/NioChatClient.java @@ -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 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); + } + } +} \ No newline at end of file diff --git a/Final/src/nio/NioChatServer.java b/Final/src/nio/NioChatServer.java new file mode 100644 index 0000000..99ea7b1 --- /dev/null +++ b/Final/src/nio/NioChatServer.java @@ -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 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 selectedKeys = selector.selectedKeys(); + Iterator 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()); + } + } +} \ No newline at end of file diff --git a/Final/src/nio/NioHttpServer.java b/Final/src/nio/NioHttpServer.java new file mode 100644 index 0000000..ff697b5 --- /dev/null +++ b/Final/src/nio/NioHttpServer.java @@ -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 selectedKeys = selector.selectedKeys(); + Iterator 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 = "

Hello NIO!

这是一个基于Java NIO的HTTP服务器响应。

"; + 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(); + } + } +} \ No newline at end of file diff --git a/Homework0520/.gitignore b/Homework0520/.gitignore new file mode 100644 index 0000000..f68d109 --- /dev/null +++ b/Homework0520/.gitignore @@ -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 \ No newline at end of file diff --git a/Homework0520/.idea/.gitignore b/Homework0520/.idea/.gitignore new file mode 100644 index 0000000..7d05e99 --- /dev/null +++ b/Homework0520/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# 依赖于环境的 Maven 主目录路径 +/mavenHomeManager.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/Homework0520/.idea/misc.xml b/Homework0520/.idea/misc.xml new file mode 100644 index 0000000..6f29fee --- /dev/null +++ b/Homework0520/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Homework0520/.idea/modules.xml b/Homework0520/.idea/modules.xml new file mode 100644 index 0000000..d33bab6 --- /dev/null +++ b/Homework0520/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Homework0520/.idea/vcs.xml b/Homework0520/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/Homework0520/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Homework0520/Homework0520.iml b/Homework0520/Homework0520.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/Homework0520/Homework0520.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Homework0520/src/BufferBasicOperations.java b/Homework0520/src/BufferBasicOperations.java new file mode 100644 index 0000000..f03a61e --- /dev/null +++ b/Homework0520/src/BufferBasicOperations.java @@ -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()); + } +} \ No newline at end of file diff --git a/Homework0520/src/BufferFlipCompact.java b/Homework0520/src/BufferFlipCompact.java new file mode 100644 index 0000000..cff4c9e --- /dev/null +++ b/Homework0520/src/BufferFlipCompact.java @@ -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()); + } +} \ No newline at end of file diff --git a/Homework0520/src/BufferMarkInvalid.java b/Homework0520/src/BufferMarkInvalid.java new file mode 100644 index 0000000..8a92c6b --- /dev/null +++ b/Homework0520/src/BufferMarkInvalid.java @@ -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()); + } +} \ No newline at end of file diff --git a/Homework0520/src/BufferMarkReset.java b/Homework0520/src/BufferMarkReset.java new file mode 100644 index 0000000..62011b7 --- /dev/null +++ b/Homework0520/src/BufferMarkReset.java @@ -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()); + } +} \ No newline at end of file diff --git a/Homework0520/src/BufferMarkerReader.java b/Homework0520/src/BufferMarkerReader.java new file mode 100644 index 0000000..3c87547 --- /dev/null +++ b/Homework0520/src/BufferMarkerReader.java @@ -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()); + } +} \ No newline at end of file diff --git a/Homework0520/src/BufferVerificationAndThinking.java b/Homework0520/src/BufferVerificationAndThinking.java new file mode 100644 index 0000000..b0f0f87 --- /dev/null +++ b/Homework0520/src/BufferVerificationAndThinking.java @@ -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()); + } +} \ No newline at end of file diff --git a/Homework0520/src/TicketSystem.java b/Homework0520/src/TicketSystem.java new file mode 100644 index 0000000..8cec726 --- /dev/null +++ b/Homework0520/src/TicketSystem.java @@ -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("✗ 验证失败:票数统计有误"); + } + + } +} \ No newline at end of file diff --git a/NIOChatServ/.gitignore b/NIOChatServ/.gitignore new file mode 100644 index 0000000..f68d109 --- /dev/null +++ b/NIOChatServ/.gitignore @@ -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 \ No newline at end of file diff --git a/NIOChatServ/.idea/.gitignore b/NIOChatServ/.idea/.gitignore new file mode 100644 index 0000000..7d05e99 --- /dev/null +++ b/NIOChatServ/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# 依赖于环境的 Maven 主目录路径 +/mavenHomeManager.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/NIOChatServ/.idea/misc.xml b/NIOChatServ/.idea/misc.xml new file mode 100644 index 0000000..6f29fee --- /dev/null +++ b/NIOChatServ/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/NIOChatServ/.idea/modules.xml b/NIOChatServ/.idea/modules.xml new file mode 100644 index 0000000..3d95b3e --- /dev/null +++ b/NIOChatServ/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/NIOChatServ/.idea/vcs.xml b/NIOChatServ/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/NIOChatServ/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/NIOChatServ/NIOChatServ.iml b/NIOChatServ/NIOChatServ.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/NIOChatServ/NIOChatServ.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/NIOChatServ/src/client/NioChatClient.java b/NIOChatServ/src/client/NioChatClient.java new file mode 100644 index 0000000..b83aa58 --- /dev/null +++ b/NIOChatServ/src/client/NioChatClient.java @@ -0,0 +1,255 @@ +package client; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.Iterator; + +public class NioChatClient extends JFrame { + + // UI 组件 + private JTextField hostField; + private JTextField portField; + private JButton connectButton; + + private JTextArea messageArea; // 显示聊天内容 + private JTextField inputField; // 输入框 + private JButton sendButton; // 发送按钮 + + // NIO相关 + private volatile SocketChannel socketChannel; + private volatile Selector selector; + private volatile boolean running = false; // 用于控制读线程 + + private Thread readThread; // 后台读取服务器消息的线程 + + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> { + NioChatClient client = new NioChatClient(); + client.setVisible(true); + }); + } + + /** + * 构造UI + */ + public NioChatClient() { + super("NIO Chat Client"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(600, 400); + + // 主机、端口输入区域 + JPanel connectPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + connectPanel.add(new JLabel("服务器主机:")); + hostField = new JTextField("127.0.0.1", 10); + connectPanel.add(hostField); + + connectPanel.add(new JLabel("端口:")); + portField = new JTextField("8888", 5); + connectPanel.add(portField); + + connectButton = new JButton("连接"); + connectPanel.add(connectButton); + + // 聊天显示区域 + messageArea = new JTextArea(); + messageArea.setEditable(false); + JScrollPane scrollPane = new JScrollPane(messageArea); + + // 发送消息区域 + JPanel inputPanel = new JPanel(new BorderLayout()); + inputField = new JTextField(); + sendButton = new JButton("发送"); + + inputPanel.add(inputField, BorderLayout.CENTER); + inputPanel.add(sendButton, BorderLayout.EAST); + + // 布局 + getContentPane().setLayout(new BorderLayout()); + getContentPane().add(connectPanel, BorderLayout.NORTH); + getContentPane().add(scrollPane, BorderLayout.CENTER); + getContentPane().add(inputPanel, BorderLayout.SOUTH); + + // 按钮事件绑定 + connectButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (!running) { + connectToServer(); + } else { + disconnectFromServer(); + } + } + }); + + sendButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + sendMessage(inputField.getText().trim()); + inputField.setText(""); + } + }); + } + + /** + * 连接到服务器 + */ + private void connectToServer() { + final String host = hostField.getText().trim(); + final int port = Integer.parseInt(portField.getText().trim()); + + try { + // 打开Selector和SocketChannel + selector = Selector.open(); + socketChannel = SocketChannel.open(); + socketChannel.configureBlocking(false); + socketChannel.connect(new InetSocketAddress(host, port)); + socketChannel.register(selector, SelectionKey.OP_CONNECT); + + // 启动后台线程,处理服务器消息 + running = true; + readThread = new Thread(this::readLoop, "NioClient-ReadThread"); + readThread.start(); + + // 更新UI状态 + connectButton.setText("断开"); + appendMessage("正在连接到服务器 " + host + ":" + port + "...\n"); + } catch (IOException e) { + appendMessage("连接失败: " + e.getMessage() + "\n"); + e.printStackTrace(); + } + } + + /** + * 断开与服务器的连接 + */ + private void disconnectFromServer() { + running = false; + try { + if (socketChannel != null) { + socketChannel.close(); + } + if (selector != null) { + selector.wakeup(); + selector.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + socketChannel = null; + selector = null; + connectButton.setText("连接"); + appendMessage("已断开连接。\n"); + } + } + + /** + * 发送消息给服务器 + */ + private void sendMessage(String msg) { + if (!running || socketChannel == null || !socketChannel.isOpen()) { + appendMessage("未连接服务器,无法发送消息。\n"); + return; + } + if (msg.isEmpty()) { + return; + } + try { + socketChannel.write(ByteBuffer.wrap((msg + "\n").getBytes())); + } catch (IOException e) { + appendMessage("发送失败: " + e.getMessage() + "\n"); + e.printStackTrace(); + } + } + + /** + * 读取服务器消息的循环线程 + */ + private void readLoop() { + try { + while (running && selector != null && selector.isOpen()) { + // 阻塞等待事件 + selector.select(); + + // 处理所有就绪事件 + Iterator it = selector.selectedKeys().iterator(); + while (it.hasNext()) { + SelectionKey key = it.next(); + it.remove(); + + if (!key.isValid()) { + continue; + } + + // 处理连接完成 + if (key.isConnectable()) { + handleConnect(key); + } + + // 处理可读 + if (key.isReadable()) { + handleRead(key); + } + } + } + } catch (IOException e) { + appendMessage("读取服务器消息时出现异常: " + e.getMessage() + "\n"); + e.printStackTrace(); + } finally { + // 读线程结束时进行清理 + disconnectFromServer(); + } + } + + /** + * 处理连接完成 + */ + private void handleConnect(SelectionKey key) throws IOException { + SocketChannel sc = (SocketChannel) key.channel(); + if (sc.isConnectionPending()) { + sc.finishConnect(); + } + sc.configureBlocking(false); + sc.register(selector, SelectionKey.OP_READ); + appendMessage("已连接到服务器。\n"); + } + + /** + * 处理可读事件:从服务器接收数据 + */ + private void handleRead(SelectionKey key) throws IOException { + SocketChannel sc = (SocketChannel) key.channel(); + ByteBuffer buffer = ByteBuffer.allocate(1024); + + int readBytes = sc.read(buffer); + if (readBytes == -1) { + // 服务器端关闭 + appendMessage("服务器已断开连接。\n"); + running = false; + return; + } + + if (readBytes > 0) { + buffer.flip(); + // 按照简单文本协议,读到换行符即可作为一条消息 + String msg = new String(buffer.array(), 0, buffer.limit()).trim(); + appendMessage(msg + "\n"); + } + } + + /** + * 在UI文本框中追加消息 (线程安全) + */ + private void appendMessage(String msg) { + SwingUtilities.invokeLater(() -> { + messageArea.append(msg); + // 自动滚动到末尾 + messageArea.setCaretPosition(messageArea.getDocument().getLength()); + }); + } +} diff --git a/NIOChatServ/src/server/NioChatServer.java b/NIOChatServ/src/server/NioChatServer.java new file mode 100644 index 0000000..0b85386 --- /dev/null +++ b/NIOChatServ/src/server/NioChatServer.java @@ -0,0 +1,153 @@ +package server; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class NioChatServer { + + // 维护所有已连接的 SocketChannel + private static final ConcurrentHashMap clientMap = new ConcurrentHashMap<>(); + + public static void main(String[] args) { + // 端口可根据需要进行修改 + int port = 8888; + try (Selector selector = Selector.open(); + ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) { + + // 配置为非阻塞 + serverSocketChannel.configureBlocking(false); + // 绑定端口 + serverSocketChannel.bind(new InetSocketAddress(port)); + // 注册到 selector,监听 "接收新连接" 事件 + serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); + + System.out.println("服务器已启动,监听端口: " + port); + + // 事件循环 + while (true) { + // 阻塞等待就绪的通道 + selector.select(); + // 获取就绪的事件集合 + Set selectionKeys = selector.selectedKeys(); + Iterator iterator = selectionKeys.iterator(); + + while (iterator.hasNext()) { + SelectionKey key = iterator.next(); + iterator.remove(); // 每次处理完一个事件后必须移除,避免重复处理 + + try { + // 处理新连接 + if (key.isAcceptable()) { + handleAccept(key, selector); + } + // 处理可读事件 + if (key.isReadable()) { + handleRead(key, selector); + } + } catch (IOException e) { + // 发生异常时关闭连接并清理 + closeChannel(key); + } + } + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 处理新客户端连接 + */ + private static void handleAccept(SelectionKey key, Selector selector) throws IOException { + ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); + SocketChannel sc = ssc.accept(); + if (sc == null) { + return; + } + // 配置为非阻塞 + sc.configureBlocking(false); + // 注册到选择器中,关注读事件 + sc.register(selector, SelectionKey.OP_READ); + // 将此客户端加入管理集合(如果需要,可以存储客户端的名称/ID等信息) + clientMap.put(sc, sc.getRemoteAddress().toString()); + System.out.println("客户端连接: " + sc.getRemoteAddress()); + } + + /** + * 处理客户端发送的数据 + */ + private static void handleRead(SelectionKey key, Selector selector) throws IOException { + SocketChannel sc = (SocketChannel) key.channel(); + ByteBuffer buffer = ByteBuffer.allocate(1024); + + int readBytes = sc.read(buffer); + // 正常关闭或异常 + if (readBytes == -1) { + closeChannel(key); + return; + } + + // 如果有数据 + if (readBytes > 0) { + buffer.flip(); + String msg = new String(buffer.array(), 0, buffer.limit()).trim(); + + System.out.println("收到消息: " + msg + " 来自: " + clientMap.get(sc)); + + // 识别特殊命令 + if ("EXIT".equalsIgnoreCase(msg)) { + // 关闭连接 + System.out.println("客户端请求断开连接: " + clientMap.get(sc)); + closeChannel(key); + } else if ("PING".equalsIgnoreCase(msg)) { + // 回复 PONG + String pong = "PONG\n"; + sc.write(ByteBuffer.wrap(pong.getBytes())); + } else { + // 普通消息进行广播 + broadcastMessage(sc, msg); + } + } + } + + /** + * 向其他所有客户端广播消息 + */ + private static void broadcastMessage(SocketChannel sender, String msg) { + // 构造广播内容 + String senderInfo = clientMap.get(sender); + String broadcastMsg = "[" + senderInfo + "] " + msg + "\n"; + + // 遍历所有连接的客户端, 写入消息 + clientMap.forEach((channel, info) -> { + if (channel != sender && channel.isOpen()) { + try { + channel.write(ByteBuffer.wrap(broadcastMsg.getBytes())); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + } + + /** + * 关闭通道,清理资源 + */ + private static void closeChannel(SelectionKey key) { + try { + SocketChannel sc = (SocketChannel) key.channel(); + System.out.println("连接关闭: " + clientMap.get(sc)); + clientMap.remove(sc); + key.cancel(); + sc.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/example_src/.gitignore b/example_src/.gitignore new file mode 100644 index 0000000..f68d109 --- /dev/null +++ b/example_src/.gitignore @@ -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 \ No newline at end of file diff --git a/example_src/.idea/.gitignore b/example_src/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/example_src/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/example_src/.idea/misc.xml b/example_src/.idea/misc.xml new file mode 100644 index 0000000..5af9c98 --- /dev/null +++ b/example_src/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/example_src/.idea/modules.xml b/example_src/.idea/modules.xml new file mode 100644 index 0000000..fc2e1fa --- /dev/null +++ b/example_src/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/example_src/.idea/vcs.xml b/example_src/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/example_src/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/example_src/Network_Communication.iml b/example_src/Network_Communication.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/example_src/Network_Communication.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/example_src/src/Bus.java b/example_src/src/Bus.java new file mode 100644 index 0000000..32003eb --- /dev/null +++ b/example_src/src/Bus.java @@ -0,0 +1,24 @@ +public class Bus implements MyPay,MyInterface2 { + + public void payMoney() { + System.out.println("Bus pay money:2元"); + + } + public void myPrint() { + System.out.println("my bus print"); + + } + public void myMethod() { + System.out.println("aggdksjal"); + } + + @Override + public void MyInter1Fun() { + + } + + @Override + public void MyInter2Fun() { + + } +} diff --git a/example_src/src/MyDemo1.java b/example_src/src/MyDemo1.java new file mode 100644 index 0000000..ccd9665 --- /dev/null +++ b/example_src/src/MyDemo1.java @@ -0,0 +1,18 @@ +class MyClass1{ + int a1; + int a2; + void myPrint(){ + System.out.println("a1 = " + a1); + } +} +class MyClass2 { + int a3; + void myPrint(){ + System.out.println("a3 = " + a3); + } +} +public class MyDemo1 extends MyClass1{ + + + +} diff --git a/example_src/src/MyInterface2.java b/example_src/src/MyInterface2.java new file mode 100644 index 0000000..49349db --- /dev/null +++ b/example_src/src/MyInterface2.java @@ -0,0 +1,3 @@ +public interface MyInterface2 { + public void myMethod(); +} diff --git a/example_src/src/MyPay.java b/example_src/src/MyPay.java new file mode 100644 index 0000000..9116316 --- /dev/null +++ b/example_src/src/MyPay.java @@ -0,0 +1,13 @@ +interface MyInter1{ + void MyInter1Fun(); +} +interface MyInter2{ + void MyInter2Fun(); + +} +public interface MyPay extends MyInter1, MyInter2 { + // int x=9; + void payMoney(); + void myPrint(); + +} diff --git a/example_src/src/MyTest1.java b/example_src/src/MyTest1.java new file mode 100644 index 0000000..1ef3ced --- /dev/null +++ b/example_src/src/MyTest1.java @@ -0,0 +1,23 @@ +public class MyTest1 { + + public static void main(String[] args) { + int a=0; + int y=100; + int z; + try{ + z=y/a; + } catch (ArithmeticException e) { + System.out.println("ArithmeticException"); + z=Integer.MAX_VALUE; + System.out.println(z); + } + + catch (Exception e) { + System.out.println("Exception"); + } + + + + } + +} \ No newline at end of file diff --git a/example_src/src/Test1.java b/example_src/src/Test1.java new file mode 100644 index 0000000..ddade1b --- /dev/null +++ b/example_src/src/Test1.java @@ -0,0 +1,32 @@ +public class Test1 implements Runnable { + public static void main(String[] args) throws InterruptedException { + System.out.println("Hello World"); + Test1 t = new Test1(); + Thread th1=new Thread(t); + th1.setName("Thread1"); + //th1.run(); + th1.start(); + + for (int i = 0; i < 10; i++) { + Thread.sleep(1000); + System.out.println("in main"); + + } + + + } + + @Override + public void run() { + for (int i = 0; i < 10; i++) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // throw new RuntimeException(e); + } + System.out.println("nantongdaxue"); + System.out.println(Thread.currentThread().getName()); + } + + } +} diff --git a/example_src/src/Test2.java b/example_src/src/Test2.java new file mode 100644 index 0000000..9fbebb2 --- /dev/null +++ b/example_src/src/Test2.java @@ -0,0 +1,14 @@ +public class Test2 { + public static void main(String[] args) { + int a = 0; + int y; + try{ + y=3/a; + }catch(ArithmeticException e){ + System.out.println("ArithmeticException"); + y=Integer.MAX_VALUE; + } + + System.out.println(y); + } +} diff --git a/example_src/src/Test3.java b/example_src/src/Test3.java new file mode 100644 index 0000000..6073b53 --- /dev/null +++ b/example_src/src/Test3.java @@ -0,0 +1,39 @@ + +class MyThread extends Thread{ + public void run(){ + for(int i=0;i<10;i++){ + try { + Thread.sleep(1000); + }catch(InterruptedException e){ + System.out.println("InterruptedException"); + } + + System.out.println("in myThread:"+Thread.currentThread().getName()); + + } + + } +} + + +public class Test3 { + public static void main(String[] args) throws InterruptedException { + MyThread t1=new MyThread(); + t1.setName("t1"); + t1.start(); + + MyThread t2=new MyThread(); + t2.setName("t2"); + t2.start(); + + for (int i = 0; i < 10; i++) { + Thread.sleep(1000); + System.out.println("in main:"+Thread.currentThread().getName()); + + } + + } + + + +} diff --git a/example_src/src/abc/C1.java b/example_src/src/abc/C1.java new file mode 100644 index 0000000..075ff4a --- /dev/null +++ b/example_src/src/abc/C1.java @@ -0,0 +1,21 @@ +package abc; + +public class C1 extends Thread{ + private char ch; + private PrintCH pc; + + public C1(char ch, PrintCH pc) { + this.ch = ch; this.pc=pc; + } + public void run(){ + pc.print(ch); + } + public static void main(String[] args) { + PrintCH pc1=new PrintCH(); + PrintCH pc2=new PrintCH(); + C1 t1=new C1('A',pc2); + C1 t2=new C1('B',pc2); + t1.start(); + t2.start(); + } +} diff --git a/example_src/src/abc/PrintCH.java b/example_src/src/abc/PrintCH.java new file mode 100644 index 0000000..01c3931 --- /dev/null +++ b/example_src/src/abc/PrintCH.java @@ -0,0 +1,14 @@ +package abc; + +public class PrintCH { + public synchronized void print(char c){ + for(int i=0;i<4;i++){ + System.out.print(c); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/example_src/src/hk1/hk1.iml b/example_src/src/hk1/hk1.iml new file mode 100644 index 0000000..6db0c46 --- /dev/null +++ b/example_src/src/hk1/hk1.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/example_src/src/hk1/src/demo1/MainTest.java b/example_src/src/hk1/src/demo1/MainTest.java new file mode 100644 index 0000000..fc33b06 --- /dev/null +++ b/example_src/src/hk1/src/demo1/MainTest.java @@ -0,0 +1,18 @@ +package demo1; + +public class MainTest { + public static void main(String[] args) { + MyThread1 t1 = new MyThread1(); + Thread myt1 = new Thread(t1); + myt1.start(); + + + MyThread2 t2 = new MyThread2(); + t2.start(); + + System.out.println("this is a main function"); + + + + } +} diff --git a/example_src/src/hk1/src/demo1/MyThread1.java b/example_src/src/hk1/src/demo1/MyThread1.java new file mode 100644 index 0000000..274e07e --- /dev/null +++ b/example_src/src/hk1/src/demo1/MyThread1.java @@ -0,0 +1,19 @@ +package demo1; + +public class MyThread1 implements Runnable { + + public void run() { + for (int i = 0; i < 10; i++) { + System.out.println("this is a car"); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + + + + } +} diff --git a/example_src/src/hk1/src/demo1/MyThread2.java b/example_src/src/hk1/src/demo1/MyThread2.java new file mode 100644 index 0000000..8efb859 --- /dev/null +++ b/example_src/src/hk1/src/demo1/MyThread2.java @@ -0,0 +1,16 @@ +package demo1; + +public class MyThread2 extends Thread { + public void run() { + for (int i = 0; i < 10; i++) { + System.out.println("this is a bus"); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + } + +} diff --git a/example_src/src/hk2/hk2.iml b/example_src/src/hk2/hk2.iml new file mode 100644 index 0000000..6db0c46 --- /dev/null +++ b/example_src/src/hk2/hk2.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/example_src/src/hk2/src/Main.java b/example_src/src/hk2/src/Main.java new file mode 100644 index 0000000..d5238c9 --- /dev/null +++ b/example_src/src/hk2/src/Main.java @@ -0,0 +1,5 @@ +public class Main { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} \ No newline at end of file diff --git a/example_src/src/pk1/MyTest.java b/example_src/src/pk1/MyTest.java new file mode 100644 index 0000000..f760de2 --- /dev/null +++ b/example_src/src/pk1/MyTest.java @@ -0,0 +1,22 @@ +package pk1; +public class MyTest extends Thread{ + private char ch; + private PrintCH2 myprint; + public MyTest(char ch, PrintCH2 myprint){ + this.ch = ch; + this.myprint = myprint; + } + public void run(){ + synchronized(myprint){ + myprint.print(ch); + } + myprint.print(ch); + } + public static void main(String[] args){ + PrintCH2 printch2 = new PrintCH2(); + MyTest t1 = new MyTest('A', myprint); + MyTest t2 = new MyTest('B', myprint); + t1.start(); + t2.start(); + } +} diff --git a/example_src/src/pk1/pk2/MyThread1.java b/example_src/src/pk1/pk2/MyThread1.java new file mode 100644 index 0000000..2bfa72e --- /dev/null +++ b/example_src/src/pk1/pk2/MyThread1.java @@ -0,0 +1,49 @@ +package pk1.pk2; +class Thread3 implements Runnable { + public void run(){ + System.out.println("in thread3"); + + } + +} + class MyThread2 extends Thread { + public void run() { + for (int i = 0; i < 10; i++) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + System.out.println("in MyThread2"+Thread.currentThread().getName()); + } + + } + + +} + +public class MyThread1 { + public static void main(String[] args) throws InterruptedException { + MyThread2 t = new MyThread2(); + t.setName("Thread2"); + t.start(); + Thread t2 = new Thread(t); + t2.setName("Thread3"); + t2.start(); + System.out.println(t2.isAlive()); + System.out.println(t.isAlive()); + + Thread3 th3 = new Thread3(); + Thread myth3 = new Thread(th3); + myth3.setName("MyThread3"); + myth3.start(); + + // Thread myth6 = new Thread("aba"); + + + for (int i = 0; i < 10; i++) { + Thread.sleep(1000); + System.out.println("nantongdaxue"); + } + } +} diff --git a/onetoone/.gitignore b/onetoone/.gitignore new file mode 100644 index 0000000..f68d109 --- /dev/null +++ b/onetoone/.gitignore @@ -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 \ No newline at end of file diff --git a/onetoone/.idea/.gitignore b/onetoone/.idea/.gitignore new file mode 100644 index 0000000..7d05e99 --- /dev/null +++ b/onetoone/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# 依赖于环境的 Maven 主目录路径 +/mavenHomeManager.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/onetoone/.idea/misc.xml b/onetoone/.idea/misc.xml new file mode 100644 index 0000000..5af9c98 --- /dev/null +++ b/onetoone/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/onetoone/.idea/modules.xml b/onetoone/.idea/modules.xml new file mode 100644 index 0000000..ce6635c --- /dev/null +++ b/onetoone/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/onetoone/.idea/runConfigurations/MyClient.xml b/onetoone/.idea/runConfigurations/MyClient.xml new file mode 100644 index 0000000..a182385 --- /dev/null +++ b/onetoone/.idea/runConfigurations/MyClient.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/onetoone/.idea/runConfigurations/MyServer.xml b/onetoone/.idea/runConfigurations/MyServer.xml new file mode 100644 index 0000000..fd8ac96 --- /dev/null +++ b/onetoone/.idea/runConfigurations/MyServer.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/onetoone/.idea/uiDesigner.xml b/onetoone/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/onetoone/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/onetoone/.idea/vcs.xml b/onetoone/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/onetoone/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/onetoone/onetoone.iml b/onetoone/onetoone.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/onetoone/onetoone.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/onetoone/src/ClientThread.java b/onetoone/src/ClientThread.java new file mode 100644 index 0000000..59a3a13 --- /dev/null +++ b/onetoone/src/ClientThread.java @@ -0,0 +1,63 @@ +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class ClientThread extends Thread { + private final MyServer serverDialog; // 添加Server1的引用 + private Socket toClientSocket = null;// 会话套接字 + private BufferedReader in; // 网络输入流 + private PrintWriter out; // 网络输出流 + private int clientCounts = 0;// 在线客户机总数 + + public ClientThread(Socket toClientSocket, int clientCounts, MyServer serverDialog) { // 构造函数 + this.toClientSocket = toClientSocket; + this.clientCounts = clientCounts; + this.serverDialog = serverDialog; + } // 保存Server1的引用 + + @Override + public void run() { + try { + // 创建绑定到套接字toClientSocket上的网络输入流与输出流 + in = new BufferedReader(new InputStreamReader(toClientSocket.getInputStream(), StandardCharsets.UTF_8)); + out = new PrintWriter(new OutputStreamWriter(toClientSocket.getOutputStream(), StandardCharsets.UTF_8), true); + // 5. 根据服务器协议,在网络流上进行读写操作 + String recvStr; + while ((recvStr = in.readLine()) != null) { // 只要客户机不关闭,则反复等待和接收客户机消息 + Date date = new Date(); + DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + String time = format.format(date); + //ServerUI.txtArea.append(toClientSocket.getRemoteSocketAddress() + " 客户机编号: " + clientCounts + " 消息:" + // + recvStr + " :" + time + "\n"); // 解析并显示收到的消息 + // 按照echo协议原封不动回送消息 + + String message = toClientSocket.getRemoteSocketAddress() + " 客户机编号: " + clientCounts + " 消息:" + recvStr + " :" + time + "\n"; + + // 使用Server1的公开方法来更新txtArea + if (serverDialog != null) { + serverDialog.appendToTextArea(message); + } + + + out.println(toClientSocket.getLocalSocketAddress() + " 客户机编号: " + clientCounts + " Echo消息:" + recvStr + + " : " + time); + } // end while + // ServerUI.clientCounts--; // 客户机总数减1 + // 远程客户机断开连接,线程释放资源 + if (in != null) + in.close(); + if (out != null) + out.close(); + if (toClientSocket != null) + toClientSocket.close(); + } catch (Exception ex) { + System.out.println(ex.getMessage()); + } + } // end run +} diff --git a/onetoone/src/MyClient.form b/onetoone/src/MyClient.form new file mode 100644 index 0000000..58f4556 --- /dev/null +++ b/onetoone/src/MyClient.form @@ -0,0 +1,151 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/onetoone/src/MyClient.java b/onetoone/src/MyClient.java new file mode 100644 index 0000000..d0f000f --- /dev/null +++ b/onetoone/src/MyClient.java @@ -0,0 +1,118 @@ +import javax.swing.*; +import java.awt.event.*; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; + +public class MyClient extends JDialog { + private JPanel contentPane; + private JPanel top; + private JTextField txtRemoteName; + private JTextField txtRemotePort; + private JPanel line1; + private JPanel line2; + private JTextField txtInput; + private JButton btnConnect; + private JButton btnSpeak; + private JPanel buttom; + private JTextArea txtArea; + + private Socket clientSocket = null; // 声明客户机套接字 + private BufferedReader in; // 声明网络输入流 + private PrintWriter out; // 声明网络输出流 + + public MyClient() { + setContentPane(contentPane); + setModal(true); + + // 点击 X 时调用 onCancel() + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // 遇到 ESCAPE 时调用 onCancel() + contentPane.registerKeyboardAction(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + btnConnect.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + // 获取服务器参数 + String remoteName = txtRemoteName.getText(); + int remotePort = Integer.parseInt(txtRemotePort.getText()); + // 构建服务器Socket格式的地址 + SocketAddress remoteAddr = new InetSocketAddress(InetAddress.getByName(remoteName), remotePort); + // 1. 创建套接字clientSocket并连接到远程服务器 + clientSocket = new Socket(); + clientSocket.connect(remoteAddr); + txtArea.append("连接服务器成功,会话开始...\n"); + // 2. 创建绑定到套接字clientSocket上的网络输入流与输出流 + out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"), true); + in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8")); + + } catch (Exception ex) { + JOptionPane.showMessageDialog(null, ex.getMessage(), "连接错误", JOptionPane.ERROR_MESSAGE); + return; + } + btnConnect.setEnabled(false); + } + }); + btnSpeak.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // 3. 根据服务器协议,在网络流上进行读写操作 + if (clientSocket == null) { + JOptionPane.showMessageDialog(null, "请先检查服务器连接情况。\n发言之前要确保客户机连接到服务器!", "错误提示", + JOptionPane.ERROR_MESSAGE); + return; + } + // 获取待发消息 + String outStr = txtInput.getText(); + if (outStr.isEmpty()) { // 待发消息框为空 + JOptionPane.showMessageDialog(null, "请输入发送消息!", "提示", JOptionPane.INFORMATION_MESSAGE); + return; + } + // 发送 + out.println(outStr); + txtInput.setText(""); + try { + // 按照echo协议,客户机应立即接收服务器回送消息 + String inStr; + inStr = in.readLine(); + // 收到的echo消息加入下面的文本框 + txtArea.append("Echo: " + inStr + "\n"); + } catch (Exception ex) { + JOptionPane.showMessageDialog(null, "客户机接收消息错误!", "错误提示", JOptionPane.ERROR_MESSAGE); + } + } + }); + } + + private void onOK() { + // 在此处添加您的代码 + dispose(); + } + + private void onCancel() { + // 必要时在此处添加您的代码 + dispose(); + } + + public static void main(String[] args) { + MyClient dialog = new MyClient(); + dialog.pack(); + dialog.setVisible(true); + System.exit(0); + } +} diff --git a/onetoone/src/MyServer.form b/onetoone/src/MyServer.form new file mode 100644 index 0000000..f5bd584 --- /dev/null +++ b/onetoone/src/MyServer.form @@ -0,0 +1,107 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/onetoone/src/MyServer.java b/onetoone/src/MyServer.java new file mode 100644 index 0000000..421e6c7 --- /dev/null +++ b/onetoone/src/MyServer.java @@ -0,0 +1,110 @@ +import javax.swing.*; +import java.awt.event.*; +import java.io.IOException; +import java.net.*; + +public class MyServer extends JDialog { + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private JTextField txtHostName; + private JTextField txtHostPort; + private JButton btnStart; + private JPanel bottom; + private JPanel top; + private JPanel middle; + private JTextArea txtArea; + + private ServerSocket listenSocket = null; // 侦听套接字 + private Socket toClientSocket = null; // 与客户机对话的套接字 + public static int clientCounts = 0; // 客户数量编号 + + public void appendToTextArea(final String text) { + //这段代码定义了一个用于更新JTextArea的方法,它确保UI更新在事件调度线程(EDT)上执行,避免了线程安全问题。 + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + txtArea.append(text); + } + }); + } + + public MyServer() { + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(buttonOK); + + // 点击 X 时调用 onCancel() + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // 遇到 ESCAPE 时调用 onCancel() + contentPane.registerKeyboardAction(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + btnStart.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + btnStart.setEnabled(false); + String hostName = txtHostName.getText();// 主机名 + int hostPort = Integer.parseInt(txtHostPort.getText());// 端口 + // 构建服务器的SocketAddress格式地址 + SocketAddress serverAddr = new InetSocketAddress(InetAddress.getByName(hostName), hostPort); + listenSocket = new ServerSocket(); // 创建侦听套接字 + listenSocket.bind(serverAddr); // 绑定到工作地址 + txtArea.append("服务器开始等待客户机连接...\n"); + } catch (Exception ex) { + JOptionPane.showMessageDialog(null, ex.getMessage(), "错误提示", JOptionPane.ERROR_MESSAGE); + return; + } + + // 创建一个匿名线程,用于侦听和接受客户机连接,并创建响应客户机的会话线程 + Thread serverThread = new Thread(new Runnable() { + @Override + public void run() { + try { + while (true) { // 处理客户机连接 + toClientSocket = listenSocket.accept();// 侦听并接受客户机连接 + clientCounts++;// 客户机数量加1 + txtArea.append(toClientSocket.getRemoteSocketAddress() + " 客户机编号: " + clientCounts + + " 会话开始...\n"); + // 创建客户线程clientThread,实现一客户一线程 + Thread clientThread = new ClientThread(toClientSocket, clientCounts,MyServer.this); + clientThread.start(); // 启动任务线程 + } // end while + } catch (IOException ex) { + JOptionPane.showMessageDialog(null, ex.getMessage(), "错误提示", JOptionPane.ERROR_MESSAGE); + } + }// end run() + }); + serverThread.start(); + } + }); + } + + private void onCancel() { + // 必要时在此处添加您的代码 + try { + if (listenSocket != null) { + listenSocket.close(); // 关闭侦听套接字 + txtArea.append("服务器停止侦听客户机连接...\n"); + } + } catch (IOException ex) { + } + dispose(); + } + + public static void main(String[] args) { + MyServer dialog = new MyServer(); + dialog.pack(); + dialog.setVisible(true); + System.exit(0); + } +} diff --git a/物联网234 张顾皓 2330110900 第一次作业.docx b/物联网234 张顾皓 2330110900 第一次作业.docx new file mode 100644 index 0000000..17ba119 Binary files /dev/null and b/物联网234 张顾皓 2330110900 第一次作业.docx differ diff --git a/物联网234 张顾皓 2330110900 第三次作业.docx b/物联网234 张顾皓 2330110900 第三次作业.docx new file mode 100644 index 0000000..8535436 Binary files /dev/null and b/物联网234 张顾皓 2330110900 第三次作业.docx differ diff --git a/物联网234 张顾皓 2330110900 第二次作业.docx b/物联网234 张顾皓 2330110900 第二次作业.docx new file mode 100644 index 0000000..34be86c Binary files /dev/null and b/物联网234 张顾皓 2330110900 第二次作业.docx differ diff --git a/物联网234班 2330110900号 张顾皓 期末考核作业2025.docx b/物联网234班 2330110900号 张顾皓 期末考核作业2025.docx new file mode 100644 index 0000000..95f5a67 Binary files /dev/null and b/物联网234班 2330110900号 张顾皓 期末考核作业2025.docx differ