第二阶段:Java进阶技能②Java I/O与网络编程

🚀 第二阶段:Java进阶技能②Java I/O与网络编程

💡 学习目标:掌握Java I/O流体系、文件操作、网络编程基础和多线程编程,构建高效的数据处理和网络通信应用

📁 Java I/O流体系

🎯 I/O流概述

🌟 I/O流:Java中处理输入输出的核心机制,用于在程序与外部数据源之间传输数据

✨ I/O流分类体系
📊 Java I/O流分类
│
├── 🔄 按数据流向分类
│   ├── 📥 输入流 (InputStream/Reader)
│   └── 📤 输出流 (OutputStream/Writer)
│
├── 🔢 按数据类型分类
│   ├── 📋 字节流 (Byte Stream)
│   │   ├── InputStream/OutputStream
│   │   └── 处理二进制数据
│   └── 📝 字符流 (Character Stream)
│       ├── Reader/Writer
│       └── 处理文本数据
│
└── 🎯 按功能分类
    ├── 🔗 节点流 (Node Stream)
    │   └── 直接连接数据源
    └── 🔧 处理流 (Processing Stream)
        └── 包装其他流,提供额外功能
🏗️ 核心流类层次结构

📋 字节流家族

// 输入流
InputStream (抽象基类)
├── FileInputStream      // 文件输入流
├── ByteArrayInputStream // 字节数组输入流
├── BufferedInputStream  // 缓冲输入流
└── ObjectInputStream    // 对象输入流

// 输出流
OutputStream (抽象基类)
├── FileOutputStream     // 文件输出流
├── ByteArrayOutputStream// 字节数组输出流
├── BufferedOutputStream // 缓冲输出流
└── ObjectOutputStream   // 对象输出流

📝 字符流家族

// 输入流
Reader (抽象基类)
├── FileReader          // 文件字符输入流
├── StringReader        // 字符串输入流
├── BufferedReader      // 缓冲字符输入流
└── InputStreamReader   // 字节流到字符流转换

// 输出流
Writer (抽象基类)
├── FileWriter          // 文件字符输出流
├── StringWriter        // 字符串输出流
├── BufferedWriter      // 缓冲字符输出流
└── OutputStreamWriter  // 字符流到字节流转换

💻 基础I/O操作实战

📝 文件读写基础示例

🎯 示例1:基础文件读写

import java.io.*;

public class BasicFileIO {
    
    // 字节流文件复制
    public static void copyFileWithBytes(String source, String target) {
        try (FileInputStream fis = new FileInputStream(source);
             FileOutputStream fos = new FileOutputStream(target)) {
            
            byte[] buffer = new byte[1024];
            int bytesRead;
            
            while ((bytesRead = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
            
            System.out.println("文件复制完成!");
            
        } catch (IOException e) {
            System.err.println("文件操作失败: " + e.getMessage());
        }
    }
    
    // 字符流文本处理
    public static void processTextFile(String filename) {
        try (BufferedReader reader = new BufferedReader(new FileReader(filename));
             BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
            
            String line;
            int lineNumber = 1;
            
            while ((line = reader.readLine()) != null) {
                // 添加行号
                writer.write(lineNumber + ": " + line);
                writer.newLine();
                lineNumber++;
            }
            
            System.out.println("文本处理完成!");
            
        } catch (IOException e) {
            System.err.println("文本处理失败: " + e.getMessage());
        }
    }
    
    public static void main(String[] args) {
        // 测试文件操作
        copyFileWithBytes("input.txt", "copy.txt");
        processTextFile("input.txt");
    }
}
🔧 缓冲流性能优化

🚀 性能对比示例

import java.io.*;
import java.time.LocalDateTime;

public class BufferedStreamDemo {
    
    // 不使用缓冲流
    public static long copyWithoutBuffer(String source, String target) {
        long startTime = System.currentTimeMillis();
        
        try (FileInputStream fis = new FileInputStream(source);
             FileOutputStream fos = new FileOutputStream(target)) {
            
            int data;
            while ((data = fis.read()) != -1) {
                fos.write(data);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return System.currentTimeMillis() - startTime;
    }
    
    // 使用缓冲流
    public static long copyWithBuffer(String source, String target) {
        long startTime = System.currentTimeMillis();
        
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(target))) {
            
            int data;
            while ((data = bis.read()) != -1) {
                bos.write(data);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return System.currentTimeMillis() - startTime;
    }
    
    public static void main(String[] args) {
        String sourceFile = "large-file.txt";
        
        long timeWithoutBuffer = copyWithoutBuffer(sourceFile, "copy1.txt");
        long timeWithBuffer = copyWithBuffer(sourceFile, "copy2.txt");
        
        System.out.println("不使用缓冲流耗时: " + timeWithoutBuffer + "ms");
        System.out.println("使用缓冲流耗时: " + timeWithBuffer + "ms");
        System.out.println("性能提升: " + (timeWithoutBuffer / (double) timeWithBuffer) + "倍");
    }
}

🎯 对象序列化

📦 序列化基础概念

🔍 序列化:将对象转换为字节序列的过程,用于对象的持久化存储或网络传输

🎯 序列化应用场景

  • 💾 对象持久化存储
  • 🌐 网络数据传输
  • 🔄 分布式系统通信
  • 💿 缓存系统实现
  • 📋 深拷贝对象

⚠️ 序列化注意事项

  • 类必须实现 Serializable 接口
  • transient 关键字标记不序列化字段
  • serialVersionUID 控制版本兼容性
  • 静态字段不会被序列化
  • 父类序列化影响子类
💻 序列化实战示例

🎯 示例2:完整序列化演示

import java.io.*;
import java.util.*;

// 可序列化的用户类
class User implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    private transient String password; // 不序列化密码
    private List<String> hobbies;
    
    public User(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
        this.hobbies = new ArrayList<>();
    }
    
    // getter和setter方法
    public void addHobby(String hobby) {
        hobbies.add(hobby);
    }
    
    @Override
    public String toString() {
        return String.format("User{name='%s', age=%d, password='%s', hobbies=%s}", 
                           name, age, password, hobbies);
    }
}

public class SerializationDemo {
    
    // 序列化对象
    public static void serializeUser(User user, String filename) {
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream(filename))) {
            
            oos.writeObject(user);
            System.out.println("用户对象序列化完成: " + filename);
            
        } catch (IOException e) {
            System.err.println("序列化失败: " + e.getMessage());
        }
    }
    
    // 反序列化对象
    public static User deserializeUser(String filename) {
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream(filename))) {
            
            User user = (User) ois.readObject();
            System.out.println("用户对象反序列化完成");
            return user;
            
        } catch (IOException | ClassNotFoundException e) {
            System.err.println("反序列化失败: " + e.getMessage());
            return null;
        }
    }
    
    public static void main(String[] args) {
        // 创建用户对象
        User user = new User("张三", 25, "secret123");
        user.addHobby("编程");
        user.addHobby("阅读");
        
        System.out.println("原始对象: " + user);
        
        // 序列化
        serializeUser(user, "user.ser");
        
        // 反序列化
        User deserializedUser = deserializeUser("user.ser");
        System.out.println("反序列化对象: " + deserializedUser);
        
        // 注意:password字段为null,因为被transient修饰
    }
}

📂 文件操作与NIO

🎯 传统I/O vs NIO

📊 对比分析
特性传统I/O (BIO)NIO (New I/O)
🔄 I/O模型阻塞式非阻塞式
📊 数据处理面向流面向缓冲区
🎯 选择器不支持支持Selector
🧵 线程模型一线程一连接一线程多连接
📈 性能适合连接数少适合连接数多
🔧 复杂度简单相对复杂

💻 NIO核心组件

🔧 Channel、Buffer、Selector

📋 NIO三大核心组件

  1. 📡 Channel(通道)

    • 双向数据传输通道
    • 类似传统I/O的流,但支持读写
    • 主要实现:FileChannel、SocketChannel、ServerSocketChannel
  2. 📦 Buffer(缓冲区)

    • 数据容器,所有数据通过Buffer处理
    • 核心属性:capacity、position、limit、mark
    • 主要类型:ByteBuffer、CharBuffer、IntBuffer等
  3. 🎯 Selector(选择器)

    • 单线程管理多个Channel
    • 事件驱动模型
    • 提高并发处理能力
💻 NIO文件操作实战

🎯 示例3:NIO文件操作

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class NIOFileDemo {

    // 使用NIO复制文件
    public static void copyFileWithNIO(String source, String target) {
        try (FileChannel sourceChannel = FileChannel.open(Paths.get(source),
                StandardOpenOption.READ);
             FileChannel targetChannel = FileChannel.open(Paths.get(target),
                StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {

            ByteBuffer buffer = ByteBuffer.allocate(1024);

            while (sourceChannel.read(buffer) > 0) {
                buffer.flip(); // 切换到读模式
                targetChannel.write(buffer);
                buffer.clear(); // 清空缓冲区
            }

            System.out.println("NIO文件复制完成!");

        } catch (IOException e) {
            System.err.println("NIO文件操作失败: " + e.getMessage());
        }
    }

    // 使用Files工具类
    public static void filesUtilDemo() {
        try {
            Path path = Paths.get("demo.txt");

            // 写入文件
            List<String> lines = List.of(
                "第一行内容",
                "第二行内容",
                "第三行内容"
            );
            Files.write(path, lines, StandardCharsets.UTF_8);

            // 读取文件
            List<String> readLines = Files.readAllLines(path, StandardCharsets.UTF_8);
            System.out.println("文件内容:");
            readLines.forEach(System.out::println);

            // 文件信息
            System.out.println("文件大小: " + Files.size(path) + " bytes");
            System.out.println("是否存在: " + Files.exists(path));
            System.out.println("是否可读: " + Files.isReadable(path));

        } catch (IOException e) {
            System.err.println("Files操作失败: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        copyFileWithNIO("input.txt", "nio-copy.txt");
        filesUtilDemo();
    }
}

🗂️ 目录遍历与文件监控

📁 目录操作实战

🎯 示例4:目录遍历与文件监控

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;

public class DirectoryOperations {

    // 递归遍历目录
    public static void walkDirectory(String dirPath) {
        try {
            Files.walkFileTree(Paths.get(dirPath), new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                    System.out.println("文件: " + file.getFileName() +
                                     " (大小: " + attrs.size() + " bytes)");
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
                    System.out.println("进入目录: " + dir.getFileName());
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
                    System.out.println("离开目录: " + dir.getFileName());
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            System.err.println("目录遍历失败: " + e.getMessage());
        }
    }

    // 文件监控
    public static void watchDirectory(String dirPath) {
        try {
            WatchService watchService = FileSystems.getDefault().newWatchService();
            Path path = Paths.get(dirPath);

            path.register(watchService,
                StandardWatchEventKinds.ENTRY_CREATE,
                StandardWatchEventKinds.ENTRY_DELETE,
                StandardWatchEventKinds.ENTRY_MODIFY);

            System.out.println("开始监控目录: " + dirPath);

            while (true) {
                WatchKey key = watchService.take();

                for (WatchEvent<?> event : key.pollEvents()) {
                    WatchEvent.Kind<?> kind = event.kind();
                    Path fileName = (Path) event.context();

                    System.out.println("检测到变化: " + kind.name() + " - " + fileName);
                }

                if (!key.reset()) {
                    break;
                }
            }

        } catch (IOException | InterruptedException e) {
            System.err.println("文件监控失败: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        // 遍历当前目录
        walkDirectory(".");

        // 监控当前目录(这会阻塞程序)
        // watchDirectory(".");
    }
}

🌐 网络编程基础

🎯 网络编程概述

🌍 网络通信基础

🔗 网络编程核心概念

🌐 网络通信模型
│
├── 📡 TCP/IP协议栈
│   ├── 应用层 (HTTP, FTP, SMTP)
│   ├── 传输层 (TCP, UDP)
│   ├── 网络层 (IP)
│   └── 数据链路层 (Ethernet)
│
├── 🔌 Socket编程
│   ├── TCP Socket (可靠连接)
│   └── UDP Socket (无连接)
│
└── 🎯 Java网络API
    ├── Socket/ServerSocket (TCP)
    ├── DatagramSocket (UDP)
    └── NIO SocketChannel

💻 TCP Socket编程

🔗 客户端-服务器通信

🎯 示例5:TCP聊天程序

// TCP服务器
import java.io.*;
import java.net.*;
import java.util.concurrent.*;

public class TCPServer {
    private static final int PORT = 8888;
    private ExecutorService threadPool;

    public TCPServer() {
        threadPool = Executors.newFixedThreadPool(10);
    }

    public void start() {
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            System.out.println("服务器启动,监听端口: " + PORT);

            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("新客户端连接: " + clientSocket.getInetAddress());

                // 为每个客户端创建处理线程
                threadPool.submit(new ClientHandler(clientSocket));
            }

        } catch (IOException e) {
            System.err.println("服务器启动失败: " + e.getMessage());
        }
    }

    // 客户端处理器
    private static class ClientHandler implements Runnable {
        private Socket socket;
        private BufferedReader reader;
        private PrintWriter writer;

        public ClientHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                writer = new PrintWriter(socket.getOutputStream(), true);

                writer.println("欢迎连接到聊天服务器!");

                String message;
                while ((message = reader.readLine()) != null) {
                    System.out.println("收到消息: " + message);

                    if ("bye".equalsIgnoreCase(message)) {
                        writer.println("再见!");
                        break;
                    }

                    // 回显消息
                    writer.println("服务器回复: " + message);
                }

            } catch (IOException e) {
                System.err.println("客户端处理异常: " + e.getMessage());
            } finally {
                closeConnection();
            }
        }

        private void closeConnection() {
            try {
                if (reader != null) reader.close();
                if (writer != null) writer.close();
                if (socket != null) socket.close();
                System.out.println("客户端连接已关闭");
            } catch (IOException e) {
                System.err.println("关闭连接异常: " + e.getMessage());
            }
        }
    }

    public static void main(String[] args) {
        new TCPServer().start();
    }
}

// TCP客户端
public class TCPClient {
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 8888;

    public void connect() {
        try (Socket socket = new Socket(SERVER_HOST, SERVER_PORT);
             BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in))) {

            System.out.println("连接到服务器成功!");

            // 启动接收消息线程
            Thread receiveThread = new Thread(() -> {
                try {
                    String serverMessage;
                    while ((serverMessage = reader.readLine()) != null) {
                        System.out.println(serverMessage);
                    }
                } catch (IOException e) {
                    System.err.println("接收消息异常: " + e.getMessage());
                }
            });
            receiveThread.start();

            // 发送消息
            System.out.println("请输入消息 (输入'bye'退出):");
            String userInput;
            while ((userInput = consoleReader.readLine()) != null) {
                writer.println(userInput);

                if ("bye".equalsIgnoreCase(userInput)) {
                    break;
                }
            }

        } catch (IOException e) {
            System.err.println("客户端连接失败: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        new TCPClient().connect();
    }
}

📡 UDP Socket编程

🚀 无连接通信

🎯 示例6:UDP通信程序

// UDP服务器
import java.net.*;
import java.io.*;

public class UDPServer {
    private static final int PORT = 9999;
    private DatagramSocket socket;

    public void start() {
        try {
            socket = new DatagramSocket(PORT);
            System.out.println("UDP服务器启动,监听端口: " + PORT);

            byte[] buffer = new byte[1024];

            while (true) {
                // 接收数据包
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                socket.receive(packet);

                String message = new String(packet.getData(), 0, packet.getLength());
                System.out.println("收到来自 " + packet.getAddress() + " 的消息: " + message);

                // 发送回复
                String reply = "服务器收到: " + message;
                byte[] replyData = reply.getBytes();
                DatagramPacket replyPacket = new DatagramPacket(
                    replyData, replyData.length, packet.getAddress(), packet.getPort());
                socket.send(replyPacket);
            }

        } catch (IOException e) {
            System.err.println("UDP服务器异常: " + e.getMessage());
        } finally {
            if (socket != null && !socket.isClosed()) {
                socket.close();
            }
        }
    }

    public static void main(String[] args) {
        new UDPServer().start();
    }
}

// UDP客户端
public class UDPClient {
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 9999;

    public void sendMessage(String message) {
        try (DatagramSocket socket = new DatagramSocket()) {

            // 发送数据
            byte[] data = message.getBytes();
            InetAddress address = InetAddress.getByName(SERVER_HOST);
            DatagramPacket packet = new DatagramPacket(data, data.length, address, SERVER_PORT);
            socket.send(packet);

            // 接收回复
            byte[] buffer = new byte[1024];
            DatagramPacket replyPacket = new DatagramPacket(buffer, buffer.length);
            socket.receive(replyPacket);

            String reply = new String(replyPacket.getData(), 0, replyPacket.getLength());
            System.out.println("服务器回复: " + reply);

        } catch (IOException e) {
            System.err.println("UDP客户端异常: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        UDPClient client = new UDPClient();

        // 发送多条消息
        client.sendMessage("Hello UDP Server!");
        client.sendMessage("这是第二条消息");
        client.sendMessage("UDP通信测试完成");
    }
}

🧵 多线程编程

🎯 线程基础概念

🔄 进程与线程

🎯 进程 vs 线程对比

特性进程 (Process)线程 (Thread)
🏠 内存空间独立内存空间共享进程内存
🔄 创建开销较大较小
📡 通信方式IPC机制共享内存
🛡️ 安全性相互隔离需要同步
💥 崩溃影响不影响其他进程可能影响整个进程

🧵 Java线程状态

📊 线程生命周期
│
NEW ──────▶ RUNNABLE ◀──▶ BLOCKED
            │    ▲           │
            ▼    │           ▼
         WAITING │      TIMED_WAITING
            │    │           │
            ▼    │           ▼
         TERMINATED ◀────────┘

💻 线程创建与管理

🚀 三种创建线程的方式

🎯 示例7:线程创建方式对比

import java.util.concurrent.*;

// 方式1:继承Thread类
class MyThread extends Thread {
    private String threadName;

    public MyThread(String name) {
        this.threadName = name;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println(threadName + " - 计数: " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println(threadName + " 被中断");
                return;
            }
        }
        System.out.println(threadName + " 执行完成");
    }
}

// 方式2:实现Runnable接口
class MyRunnable implements Runnable {
    private String taskName;

    public MyRunnable(String name) {
        this.taskName = name;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println(taskName + " - 执行: " + i);
            try {
                Thread.sleep(800);
            } catch (InterruptedException e) {
                System.out.println(taskName + " 被中断");
                return;
            }
        }
        System.out.println(taskName + " 任务完成");
    }
}

// 方式3:实现Callable接口
class MyCallable implements Callable<String> {
    private String taskName;
    private int computeTime;

    public MyCallable(String name, int time) {
        this.taskName = name;
        this.computeTime = time;
    }

    @Override
    public String call() throws Exception {
        System.out.println(taskName + " 开始计算...");

        int sum = 0;
        for (int i = 1; i <= computeTime; i++) {
            sum += i;
            Thread.sleep(100); // 模拟计算时间
        }

        String result = taskName + " 计算结果: " + sum;
        System.out.println(result);
        return result;
    }
}

public class ThreadCreationDemo {

    public static void main(String[] args) {
        System.out.println("=== 线程创建方式演示 ===");

        // 方式1:继承Thread
        System.out.println("\n1. 继承Thread类:");
        MyThread thread1 = new MyThread("Thread-1");
        MyThread thread2 = new MyThread("Thread-2");
        thread1.start();
        thread2.start();

        // 等待Thread方式的线程完成
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 方式2:实现Runnable
        System.out.println("\n2. 实现Runnable接口:");
        Thread runnableThread1 = new Thread(new MyRunnable("Runnable-1"));
        Thread runnableThread2 = new Thread(new MyRunnable("Runnable-2"));
        runnableThread1.start();
        runnableThread2.start();

        // 等待Runnable方式的线程完成
        try {
            runnableThread1.join();
            runnableThread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 方式3:使用Callable和Future
        System.out.println("\n3. 实现Callable接口:");
        ExecutorService executor = Executors.newFixedThreadPool(2);

        Future<String> future1 = executor.submit(new MyCallable("Callable-1", 10));
        Future<String> future2 = executor.submit(new MyCallable("Callable-2", 15));

        try {
            // 获取计算结果
            String result1 = future1.get(); // 阻塞等待结果
            String result2 = future2.get();

            System.out.println("获取到结果1: " + result1);
            System.out.println("获取到结果2: " + result2);

        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }

        System.out.println("\n所有线程执行完成!");
    }
}

🔒 线程同步与安全

⚠️ 线程安全问题

🚨 常见线程安全问题

  • 🔄 竞态条件:多线程同时访问共享资源
  • 💥 数据不一致:读写操作不原子化
  • 🔒 死锁:线程相互等待资源
  • 🌀 活锁:线程不断重试但无法进展
  • 😴 饥饿:线程长期无法获得资源
🛡️ 同步机制实战

🎯 示例8:线程同步解决方案

import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import java.util.concurrent.atomic.AtomicInteger;

// 银行账户类 - 演示线程安全
class BankAccount {
    private double balance;
    private final ReentrantLock lock = new ReentrantLock();

    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }

    // 使用synchronized关键字
    public synchronized void depositSync(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println(Thread.currentThread().getName() +
                             " 存款: " + amount + ", 余额: " + balance);
        }
    }

    // 使用ReentrantLock
    public void depositLock(double amount) {
        lock.lock();
        try {
            if (amount > 0) {
                balance += amount;
                System.out.println(Thread.currentThread().getName() +
                                 " 存款: " + amount + ", 余额: " + balance);
            }
        } finally {
            lock.unlock();
        }
    }

    // 不安全的取款方法(演示问题)
    public void withdrawUnsafe(double amount) {
        if (balance >= amount) {
            // 模拟处理时间
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }

            balance -= amount;
            System.out.println(Thread.currentThread().getName() +
                             " 取款: " + amount + ", 余额: " + balance);
        } else {
            System.out.println(Thread.currentThread().getName() +
                             " 取款失败,余额不足: " + balance);
        }
    }

    // 安全的取款方法
    public synchronized void withdrawSafe(double amount) {
        if (balance >= amount) {
            balance -= amount;
            System.out.println(Thread.currentThread().getName() +
                             " 取款: " + amount + ", 余额: " + balance);
        } else {
            System.out.println(Thread.currentThread().getName() +
                             " 取款失败,余额不足: " + balance);
        }
    }

    public synchronized double getBalance() {
        return balance;
    }
}

// 生产者-消费者模式
class ProducerConsumerDemo {
    private final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
    private final AtomicInteger counter = new AtomicInteger(0);

    // 生产者
    class Producer implements Runnable {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 20; i++) {
                    int item = counter.incrementAndGet();
                    queue.put(item);
                    System.out.println("生产者生产: " + item + ", 队列大小: " + queue.size());
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    // 消费者
    class Consumer implements Runnable {
        private String name;

        public Consumer(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    Integer item = queue.take();
                    System.out.println(name + " 消费: " + item + ", 队列大小: " + queue.size());
                    Thread.sleep(200);

                    if (item >= 20) break; // 结束条件
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public void start() {
        ExecutorService executor = Executors.newFixedThreadPool(4);

        // 启动1个生产者和3个消费者
        executor.submit(new Producer());
        executor.submit(new Consumer("消费者-1"));
        executor.submit(new Consumer("消费者-2"));
        executor.submit(new Consumer("消费者-3"));

        executor.shutdown();
    }
}

public class ThreadSafetyDemo {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== 线程安全演示 ===");

        // 1. 银行账户线程安全测试
        System.out.println("\n1. 银行账户操作:");
        BankAccount account = new BankAccount(1000);

        ExecutorService executor = Executors.newFixedThreadPool(5);

        // 多线程同时存款
        for (int i = 0; i < 5; i++) {
            final int amount = (i + 1) * 100;
            executor.submit(() -> account.depositSync(amount));
        }

        // 多线程同时取款
        for (int i = 0; i < 3; i++) {
            final int amount = 200;
            executor.submit(() -> account.withdrawSafe(amount));
        }

        executor.shutdown();
        executor.awaitTermination(5, TimeUnit.SECONDS);

        System.out.println("最终余额: " + account.getBalance());

        // 2. 生产者-消费者模式
        System.out.println("\n2. 生产者-消费者模式:");
        ProducerConsumerDemo demo = new ProducerConsumerDemo();
        demo.start();

        Thread.sleep(10000); // 等待演示完成
        System.out.println("\n线程安全演示完成!");
    }
}

🔄 并发编程进阶

🎯 线程池技术

🏊‍♂️ 线程池优势与原理

🎯 线程池核心优势

  • 🚀 降低资源消耗:重用已创建的线程
  • 提高响应速度:任务到达时无需创建线程
  • 🎛️ 提高可管理性:统一分配、调优和监控
  • 🛡️ 控制并发数:避免系统资源耗尽

📊 Java线程池体系

🏊‍♂️ Executor框架
│
├── Executor (接口)
├── ExecutorService (接口)
├── AbstractExecutorService (抽象类)
└── ThreadPoolExecutor (核心实现)
    ├── FixedThreadPool
    ├── CachedThreadPool
    ├── SingleThreadExecutor
    └── ScheduledThreadPool
💻 线程池实战应用

🎯 示例9:线程池全面应用

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class ThreadPoolDemo {

    // 自定义线程工厂
    static class CustomThreadFactory implements ThreadFactory {
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        public CustomThreadFactory(String namePrefix) {
            this.namePrefix = namePrefix;
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r, namePrefix + "-" + threadNumber.getAndIncrement());
            thread.setDaemon(false);
            return thread;
        }
    }

    // 模拟任务
    static class Task implements Runnable {
        private final String taskName;
        private final int executionTime;

        public Task(String taskName, int executionTime) {
            this.taskName = taskName;
            this.executionTime = executionTime;
        }

        @Override
        public void run() {
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
            System.out.println(String.format("[%s] %s 开始执行任务: %s",
                             timestamp, Thread.currentThread().getName(), taskName));

            try {
                Thread.sleep(executionTime * 1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }

            timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
            System.out.println(String.format("[%s] %s 完成任务: %s",
                             timestamp, Thread.currentThread().getName(), taskName));
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== 线程池应用演示 ===");

        // 1. 固定大小线程池
        System.out.println("\n1. FixedThreadPool演示:");
        ExecutorService fixedPool = Executors.newFixedThreadPool(3);

        for (int i = 1; i <= 6; i++) {
            fixedPool.submit(new Task("Fixed-Task-" + i, 2));
        }

        fixedPool.shutdown();
        fixedPool.awaitTermination(15, TimeUnit.SECONDS);

        // 2. 自定义线程池
        System.out.println("\n2. 自定义ThreadPoolExecutor:");
        ThreadPoolExecutor customPool = new ThreadPoolExecutor(
            2,                              // 核心线程数
            4,                              // 最大线程数
            60L,                            // 空闲线程存活时间
            TimeUnit.SECONDS,               // 时间单位
            new LinkedBlockingQueue<>(2),   // 工作队列
            new CustomThreadFactory("Custom"), // 线程工厂
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
        );

        // 提交任务测试线程池行为
        for (int i = 1; i <= 8; i++) {
            try {
                customPool.submit(new Task("Custom-Task-" + i, 3));
                System.out.println("提交任务 " + i + " - 活跃线程: " + customPool.getActiveCount() +
                                 ", 队列大小: " + customPool.getQueue().size());
            } catch (RejectedExecutionException e) {
                System.out.println("任务 " + i + " 被拒绝执行");
            }
        }

        customPool.shutdown();
        customPool.awaitTermination(20, TimeUnit.SECONDS);

        // 3. 定时任务线程池
        System.out.println("\n3. ScheduledThreadPool演示:");
        ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2);

        // 延迟执行
        scheduledPool.schedule(() -> {
            System.out.println("延迟3秒执行的任务");
        }, 3, TimeUnit.SECONDS);

        // 固定频率执行
        ScheduledFuture<?> periodicTask = scheduledPool.scheduleAtFixedRate(() -> {
            System.out.println("每2秒执行一次: " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
        }, 1, 2, TimeUnit.SECONDS);

        // 10秒后取消定时任务
        scheduledPool.schedule(() -> {
            periodicTask.cancel(false);
            System.out.println("定时任务已取消");
        }, 10, TimeUnit.SECONDS);

        Thread.sleep(12000);
        scheduledPool.shutdown();

        System.out.println("\n线程池演示完成!");
    }
}

🔒 高级同步工具

🛠️ JUC并发工具类

🎯 示例10:并发工具类应用

import java.util.concurrent.*;
import java.util.Random;

public class ConcurrentUtilsDemo {

    // CountDownLatch演示 - 等待多个线程完成
    static class CountDownLatchDemo {
        public static void demo() throws InterruptedException {
            System.out.println("=== CountDownLatch演示 ===");

            int workerCount = 5;
            CountDownLatch latch = new CountDownLatch(workerCount);
            ExecutorService executor = Executors.newFixedThreadPool(workerCount);

            // 启动工作线程
            for (int i = 1; i <= workerCount; i++) {
                final int workerId = i;
                executor.submit(() -> {
                    try {
                        System.out.println("工作线程 " + workerId + " 开始工作");
                        Thread.sleep(new Random().nextInt(3000) + 1000);
                        System.out.println("工作线程 " + workerId + " 完成工作");
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    } finally {
                        latch.countDown(); // 完成一个任务
                    }
                });
            }

            System.out.println("主线程等待所有工作完成...");
            latch.await(); // 等待所有任务完成
            System.out.println("所有工作线程完成,主线程继续执行");

            executor.shutdown();
        }
    }

    // CyclicBarrier演示 - 同步屏障
    static class CyclicBarrierDemo {
        public static void demo() throws InterruptedException {
            System.out.println("\n=== CyclicBarrier演示 ===");

            int participantCount = 4;
            CyclicBarrier barrier = new CyclicBarrier(participantCount, () -> {
                System.out.println("🎉 所有参与者都到达屏障,开始下一阶段!");
            });

            ExecutorService executor = Executors.newFixedThreadPool(participantCount);

            for (int i = 1; i <= participantCount; i++) {
                final int participantId = i;
                executor.submit(() -> {
                    try {
                        // 第一阶段工作
                        System.out.println("参与者 " + participantId + " 完成第一阶段");
                        Thread.sleep(new Random().nextInt(2000) + 500);
                        barrier.await(); // 等待其他参与者

                        // 第二阶段工作
                        System.out.println("参与者 " + participantId + " 开始第二阶段");
                        Thread.sleep(new Random().nextInt(1500) + 500);
                        System.out.println("参与者 " + participantId + " 完成第二阶段");

                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                });
            }

            Thread.sleep(8000);
            executor.shutdown();
        }
    }

    // Semaphore演示 - 信号量控制资源访问
    static class SemaphoreDemo {
        public static void demo() throws InterruptedException {
            System.out.println("\n=== Semaphore演示 ===");

            // 模拟3个停车位
            Semaphore parkingLot = new Semaphore(3);
            ExecutorService executor = Executors.newFixedThreadPool(8);

            for (int i = 1; i <= 8; i++) {
                final int carId = i;
                executor.submit(() -> {
                    try {
                        System.out.println("汽车 " + carId + " 尝试进入停车场");
                        parkingLot.acquire(); // 获取停车位

                        System.out.println("🚗 汽车 " + carId + " 成功停车,剩余车位: " +
                                         parkingLot.availablePermits());

                        // 停车时间
                        Thread.sleep(new Random().nextInt(3000) + 1000);

                        System.out.println("🚙 汽车 " + carId + " 离开停车场");

                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    } finally {
                        parkingLot.release(); // 释放停车位
                    }
                });
            }

            Thread.sleep(12000);
            executor.shutdown();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        CountDownLatchDemo.demo();
        CyclicBarrierDemo.demo();
        SemaphoreDemo.demo();

        System.out.println("\n并发工具类演示完成!");
    }
}

🎯 综合实战练习

📊 练习1:多线程文件处理器 ⭐⭐⭐⭐

📝 练习描述

设计一个多线程文件处理系统,能够并发处理多个文件,支持不同的处理策略和进度监控。

🎯 学习目标
  • 掌握多线程文件I/O操作
  • 理解线程池的实际应用
  • 学会设计并发安全的系统
  • 掌握进度监控和异常处理
📋 具体要求

基础要求:

  1. 支持多种文件处理操作(复制、压缩、加密等)
  2. 使用线程池管理工作线程
  3. 实现处理进度监控
  4. 提供异常处理和恢复机制

进阶要求:
5. 支持大文件的分块处理
6. 实现处理结果的统计和报告
7. 提供可配置的处理策略
8. 支持处理任务的暂停和恢复

💡 实现提示
public class FileProcessor {
    private final ExecutorService threadPool;
    private final ConcurrentHashMap<String, ProcessingTask> tasks;

    public interface ProcessingStrategy {
        void process(Path source, Path target, ProgressCallback callback) throws IOException;
    }

    public class ProcessingTask {
        private final String taskId;
        private final Path sourceFile;
        private final Path targetFile;
        private final ProcessingStrategy strategy;
        private volatile ProcessingStatus status;
        private final AtomicLong processedBytes;

        public Future<ProcessingResult> submit() {
            return threadPool.submit(() -> {
                // 实现文件处理逻辑
                return executeProcessing();
            });
        }
    }
}

🌐 练习2:NIO聊天服务器 ⭐⭐⭐⭐⭐

📝 练习描述

使用Java NIO技术实现一个高性能的聊天服务器,支持多客户端连接、消息广播和私聊功能。

🎯 学习目标
  • 掌握NIO非阻塞I/O编程
  • 理解Selector多路复用机制
  • 学会设计高并发网络应用
  • 掌握网络协议设计
📋 具体要求

基础要求:

  1. 使用NIO实现非阻塞服务器
  2. 支持多客户端同时连接
  3. 实现消息广播功能
  4. 提供用户登录和认证

进阶要求:
5. 支持私聊和群聊功能
6. 实现消息持久化存储
7. 提供在线用户列表
8. 支持文件传输功能

💡 实现提示
public class NIOChatServer {
    private Selector selector;
    private ServerSocketChannel serverChannel;
    private final Map<SocketChannel, User> clients = new ConcurrentHashMap<>();

    public void start(int port) throws IOException {
        selector = Selector.open();
        serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        serverChannel.bind(new InetSocketAddress(port));
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();
            handleSelectedKeys();
        }
    }

    private void handleSelectedKeys() {
        // 处理选择器事件
    }
}

🔄 练习3:生产者消费者框架 ⭐⭐⭐⭐

📝 练习描述

设计一个通用的生产者-消费者框架,支持多种队列类型、批量处理和流量控制。

🎯 学习目标
  • 深入理解生产者-消费者模式
  • 掌握阻塞队列的使用
  • 学会设计可扩展的框架
  • 理解流量控制机制
📋 具体要求

基础要求:

  1. 支持多个生产者和消费者
  2. 提供多种队列实现选择
  3. 实现优雅的启动和关闭
  4. 提供监控和统计功能

进阶要求:
5. 支持批量处理模式
6. 实现动态流量控制
7. 提供消息持久化选项
8. 支持消息优先级处理

💡 实现提示
public class ProducerConsumerFramework<T> {
    private final BlockingQueue<T> queue;
    private final List<Producer<T>> producers;
    private final List<Consumer<T>> consumers;
    private final ExecutorService executorService;

    public static class Builder<T> {
        public Builder<T> withQueueType(QueueType type) { return this; }
        public Builder<T> withProducerCount(int count) { return this; }
        public Builder<T> withConsumerCount(int count) { return this; }
        public ProducerConsumerFramework<T> build() { return new ProducerConsumerFramework<>(this); }
    }
}

✅ 完成标准

🎯 基础完成标准
  • 所有基本功能正常工作
  • 代码结构清晰,注释完整
  • 异常处理恰当
  • 线程安全考虑周全
  • 通过基本测试用例
🚀 进阶完成标准
  • 性能优化合理
  • 支持配置和扩展
  • 提供完整的监控信息
  • 错误恢复机制完善
  • 通过压力测试
🏆 专家级标准
  • 设计模式应用恰当
  • 代码可维护性高
  • 文档和示例完整
  • 支持生产环境部署
  • 性能达到预期指标

💡 学习建议

🎯 练习顺序
  1. 先完成基础练习,掌握单个技术点
  2. 再进行综合练习,学会技术整合
  3. 最后挑战高级项目,提升系统设计能力
🔍 重点关注
  • I/O流:选择合适的流类型,注意资源管理
  • NIO:理解非阻塞模型,掌握Buffer和Channel
  • 网络编程:协议设计、连接管理、异常处理
  • 多线程:线程安全、性能优化、资源竞争
  • 并发工具:选择合适的同步机制和并发容器

📝 本章小结

🎯 核心知识点回顾

📁 I/O流体系
  • ✅ 掌握字节流和字符流的使用场景
  • ✅ 理解缓冲流的性能优化原理
  • ✅ 熟练使用对象序列化机制
  • ✅ 掌握资源管理和异常处理
📂 NIO技术
  • ✅ 理解Channel、Buffer、Selector核心概念
  • ✅ 掌握非阻塞I/O编程模型
  • ✅ 熟练使用Files工具类
  • ✅ 实现文件监控和目录遍历
🌐 网络编程
  • ✅ 掌握TCP和UDP Socket编程
  • ✅ 理解客户端-服务器通信模式
  • ✅ 学会设计网络协议
  • ✅ 处理网络异常和连接管理
🧵 多线程编程
  • ✅ 掌握三种线程创建方式
  • ✅ 理解线程生命周期和状态转换
  • ✅ 熟练使用同步机制解决线程安全问题
  • ✅ 掌握生产者-消费者模式
🔄 并发编程
  • ✅ 熟练使用线程池管理线程资源
  • ✅ 掌握JUC并发工具类的应用
  • ✅ 理解并发容器和原子类
  • ✅ 学会设计高并发系统

📈 学习成果检验

🎯 自我检测清单
  • 能够选择合适的I/O流处理不同类型的数据
  • 理解NIO与传统I/O的区别和适用场景
  • 掌握TCP和UDP网络编程的基本技能
  • 能够设计线程安全的多线程程序
  • 熟练使用线程池和并发工具类
  • 了解各种技术的性能特点和最佳实践
🚀 进阶学习方向
方向内容推荐资源
🔧 高性能I/ONetty框架、零拷贝技术Netty官方文档
🌐 分布式通信RPC框架、消息队列Dubbo、RocketMQ
🧵 并发编程深入JMM、CAS、AQS原理《Java并发编程实战》
📊 性能调优JVM调优、并发性能分析JProfiler、VisualVM

🗺️ 专栏学习路径图

📈 Java程序员从0到1成长路径
🎯 第一阶段:Java基础入门 (4-6周) - ✅ 已完成
┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│ 1.开发环境   │───▶│ 2.基础语法   │───▶│ 3.面向对象   │───▶│ 4.核心API   │
│   搭建      │    │             │    │   编程基础   │    │             │
│ ✅ 已完成    │    │ ✅ 已完成    │    │ ✅ 已完成    │    │ ✅ 已完成    │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘

🚀 第二阶段:Java进阶技能 (4-6周)
┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│ 1.高级特性   │    │ 2.I/O与网络  │    │ 3.新特性     │    │ 4.工具框架   │
│             │    │   编程      │    │             │    │   入门      │
│ ✅ 已完成    │    │ ✅ 已完成    │    │ 🎯 下一步    │    │ 📅 计划中    │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘

🎯 第三阶段:项目实战 (4-8周)
┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│ 1.小型项目   │    │ 2.Web开发    │    │ 3.Spring    │    │ 4.数据库与   │
│   开发      │    │   基础      │    │   框架入门   │    │   持久层    │
│ 📅 计划中    │    │ 📅 计划中    │    │ 📅 计划中    │    │ 📅 计划中    │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘

🏆 第四阶段:职业发展 (持续更新)
┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│ 1.代码质量   │    │ 2.开发工具   │    │ 3.面试准备   │    │ 4.职业规划   │
│   与规范    │    │   链        │    │             │    │             │
│ 📅 计划中    │    │ 📅 计划中    │    │ 📅 计划中    │    │ 📅 计划中    │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘
📊 第二阶段详细进度
章节主要内容预计时间难度状态
🔧 1.Java高级特性泛型、反射、注解、枚举1-2周⭐⭐⭐⭐✅ 已完成
📁 2.I/O与网络编程文件操作、网络通信、多线程1-2周⭐⭐⭐⭐✅ 已完成
🆕 3.Java新特性Lambda、Stream API、模块化1周⭐⭐⭐⭐🎯 下一步
🛠️ 4.工具与框架入门Maven/Gradle、JUnit、日志框架1周⭐⭐⭐📅 计划中
🎯 当前进度
• 第二阶段进度:50% (2/4章节完成)
• 下一步:学习Java新特性
• 建议:巩固I/O和多线程知识,准备学习现代Java特性
• 重点:掌握Lambda表达式、Stream API和函数式编程

🎬 下一章预告

🆕 第二阶段第3章:Java新特性

🎯 下章学习内容

  • 🔗 Lambda表达式与函数式编程
  • 🌊 Stream API与数据处理
  • 📦 模块化系统(Java 9+)
  • ⏰ 新的日期时间API

💡 学习建议

  • 理解函数式编程思想
  • 掌握Stream API的强大功能
  • 学会使用新特性简化代码
  • 了解Java版本演进历程

🎉 恭喜完成Java I/O与网络编程的学习!

你已经掌握了Java中重要的I/O处理、网络通信和并发编程技能,
这些技术是构建高性能、高并发应用程序的重要基础!

继续保持学习的热情,向着Java专家的目标前进! 🚀


📧 有问题?欢迎在评论区讨论交流!
⭐ 觉得有用?别忘了点赞收藏!
🔄 继续关注,更多精彩内容即将到来!
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值