小米训练营day1学习内容(下)Java 函数式编程、并发编程与 JVM 原理学习总结

Java 函数式编程、并发编程与 JVM 原理学习总结


一、Java 函数式编程

1. 核心概念

  • 函数式接口:仅包含一个抽象方法的接口
    @FunctionalInterface
    interface MyFunction {
        int apply(int a, int b);
    }
    
  • Lambda表达式(参数) -> 表达式
    MyFunction add = (a, b) -> a + b;
    
  • 方法引用
    List<String> names = Arrays.asList("Alice", "Bob");
    names.forEach(System.out::println); // 实例方法引用
    

2. Stream API

List<Integer> numbers = Arrays.asList(1,2,3,4,5);
List<Integer> squares = numbers.stream()
                             .map(n -> n * n)
                             .collect(Collectors.toList());

二、Java 并发编程

1. 线程创建方式对比

方式优点缺点
继承Thread简单直接无法继承其他类
实现Runnable支持多继承无返回值
实现Callable支持返回值/异常需要配合FutureTask使用

2. 线程安全问题

// 使用AtomicInteger保证原子性
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet();

// 同步代码块示例
synchronized(lock) {
    // 临界区代码
}

三、JVM 原理深度解析

1. 内存模型(重点)

JVM内存结构
线程私有
线程共享
程序计数器
虚拟机栈
本地方法栈
方法区
运行时常量池
典型内存溢出场景
// 堆内存溢出示例
List<byte[]> list = new ArrayList<>();
while(true) {
    list.add(new byte[1024*1024]); // 不断创建1MB数组
}

// 元空间溢出示例(JDK8+)
List<Class<?>> classes = new ArrayList<>();
while(true) {
    classes.add(new ClassLoader(){}.defineClass("MyClass", new byte[1024], 0, 1024));
}

2. 类加载机制

双亲委派流程

  1. 应用程序类加载器 → 扩展类加载器 → 启动类加载器
  2. 父加载器无法加载时,才由子加载器加载

破坏双亲委派的场景

  • SPI 服务加载(如JDBC)
  • OSGi 模块化系统

3. 垃圾回收机制

垃圾判定算法对比
算法优点缺点
引用计数法实时回收循环引用问题
可达性分析解决循环引用需要STW暂停
GC日志分析示例
[GC (Allocation Failure) [PSYoungGen: 65536K->1024K(76288K)] 
  65536K->1124K(251392K), 0.0023456 secs]
  • PSYoungGen:Parallel Scavenge收集器
  • Allocation Failure:触发GC的原因
  • 前后堆内存变化:年轻代回收效果

四、线上问题排查实战

1. 常见问题排查工具链

现象发现
基础命令
jps/jinfo
jstat
jstack
jmap
VisualVM
MAT

2. 内存泄漏排查流程

  1. 生成堆转储文件
    jmap -dump:format=b,file=heap.bin <pid>
    
  2. 使用MAT分析
    • 查找Dominator Tree中的大对象
    • 分析GC Roots引用链

3. CPU飙高问题定位

top -Hp <pid>          # 查看高CPU线程
printf "%x\n" 12345    # 转换线程ID为16进制
jstack <pid> | grep 0x3039 -A 30  # 查看线程栈

五、实战问题解析

问题1:内存溢出代码分析

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    while (true) {
        list.add(new String(new char[1024 * 1024]));
    }
}

问题原因:在无限循环中不断创建1MB大小的字符串对象,导致堆内存耗尽

解决方案

  1. 增加JVM堆大小:-Xmx4g
  2. 检查业务逻辑是否存在内存泄漏
  3. 使用内存分析工具定位大对象

问题2:并发文件处理

ExecutorService executor = Executors.newFixedThreadPool(4);
List<String> sharedData = Collections.synchronizedList(new ArrayList<>());

// 使用函数式接口处理文件
Function<Path, List<String>> fileProcessor = path -> {
    try {
        return Files.readAllLines(path);
    } catch (IOException e) {
        return Collections.emptyList();
    }
};

// 内存监控线程
new Thread(() -> {
    while(true) {
        if (sharedData.size() > 100_000) {
            System.out.println("内存警告!");
        }
        Thread.sleep(1000);
    }
}).start();

六、关键总结

  1. 函数式编程:通过Lambda+Stream实现声明式编程,提高代码可读性
  2. 并发安全:合理使用synchronized/Lock/原子类保证线程安全
  3. JVM核心
    • 堆内存管理是性能调优重点
    • 类加载机制保障Java生态安全
    • GC算法选择直接影响系统吞吐
  4. 线上排查
    • 内存问题优先使用MAT分析堆转储
    • CPU问题通过线程栈定位热点代码
    • 结合Arthas实现动态诊断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值