楼主: Cabbage1123
跳转到指定楼层
上一主题 下一主题
收起左侧

学习记录贴

🔗
 楼主| Cabbage1123 2024-9-2 11:00:35 来自APP | 只看该作者
全局:
本帖最后由 Cabbage1123 于 2024-9-1 20:02 编辑

2024-09-01
今天出去玩了半天,有钱真好,可以买各种各样好玩的东西。买了橡皮船(Amazons上卖的香蕉船),还有桨板,还有Rafting用的漂浮圈,这两天到了。
迫不及待去Deer lake划船,用自己买的船的好处就是不用有时间焦虑,想玩多久玩多久,想停多久就停多久。真的好开心,好自由。

回家学习Java,在这里总结一下 Java 8 ~ Java 21 各个版本的特性(Chatgpt告诉我的)

补充内容 (2024-09-02 11:02 +08:00):

Java 8 到 Java 17 之间的版本引入了许多新特性和改进。以下是每个版本中新增和重要的变化的详细介绍:Java 8 (2014年3月)

Java 8 是一个具有里程碑意义的版本,带来了许多新的特性:
  • Lambda 表达式:这是 Java 8 的主要特性,允许在代码中使用函数式编程风格。例如:
    List<String> list = Arrays.asList("a", "b", "c");
    list.forEach(s -> System.out.println(s));
  • 函数式接口:引入了 @FunctionalInterface 注解,确保接口中只能有一个抽象方法,例如 Runnable 和 Comparator。
  • Stream API:允许以声明性方式处理集合的操作链,例如过滤、映射和减少:
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
    List<Integer> squares = numbers.stream()
                                    .map(n -> n * n)
                                    .collect(Collectors.toList());
  • 默认方法:接口可以有默认方法,这意味着接口可以有方法的默认实现。
  • Optional 类:用于防止空指针异常(NullPointerException),表示可能存在或不存在的值。
  • 新的日期时间 API:引入了 java.time 包,它提供了更好的日期和时间处理方式,例如 LocalDate, LocalTime, LocalDateTime, 和 ZonedDateTime。
  • Nashorn JavaScript 引擎:替代 Rhino,提供更好的 Java 与 JavaScript 之间的互操作性。
  • 并行数组:java.util.Arrays 提供的并行排序、并行设置和并行填充方法,用于多线程操作。
Java 9 (2017年9月)

Java 9 引入了几个重要的特性,特别是在模块化方面:
  • 模块系统 (Project Jigsaw):引入了模块化系统 (java modules),使得开发者可以将应用程序拆分成更小、更可管理的模块。模块描述符放在 module-info.java 文件中。
  • JShell:交互式编程工具,允许开发者在命令行上测试 Java 代码片段。
  • 集合工厂方法:在 List, Set, 和 Map 中添加了方便的工厂方法,可以轻松创建不可变集合:
    List<String> list = List.of("a", "b", "c");
  • 流 (Stream) API 增强:新增了方法,例如 takeWhile, dropWhile 和 iterate,以增强 Stream 操作的灵活性。
  • 私有接口方法:可以在接口中定义私有方法,以供默认方法或静态方法使用,增强了代码的模块化和重用性。
  • 改进的编译器和性能:Java 9 改进了 JIT 编译器,增强了启动时间和内存占用优化。
Java 10 (2018年3月)

Java 10 是一个短期支持版本,主要引入了一些小的改进和新特性:
  • 局部变量类型推断 (var):允许在局部变量的声明中使用 var 关键字,由编译器推断类型:
    var list = new ArrayList<String>();
  • GC 改进:引入了并行全局垃圾回收器 G1 和其它垃圾回收器的性能改进。
  • 应用类数据共享 (AppCDS):允许将应用程序类加载器加载的类数据共享在多个 Java 虚拟机实例之间,减少启动时间和内存占用。
  • 根证书:将默认的根证书直接包含在 JDK 中,增强了安全性。
Java 11 (2018年9月)

Java 11 是一个长期支持 (LTS) 版本,提供了许多改进和一些重要的新特性:
  • 新的字符串方法:例如 isBlank(), lines(), strip(), repeat(int),这些方法增强了字符串操作的便捷性。
  • HttpClient API:标准化了 java.net.http 包,提供了同步和异步的 HTTP 客户端支持,替代了原先的 HttpURLConnection。
  • 局部变量推断增强:var 关键字支持 lambda 表达式中的局部变量。
  • 废弃和移除
    • 移除了 Java EE 和 CORBA 模块。
    • 废弃了 Nashorn JavaScript 引擎。
  • 运行 Java 文件:可以直接使用 java 命令运行单个 Java 源文件,无需显式编译:
    java HelloWorld.java
Java 12 (2019年3月)

Java 12 主要引入了一些实验性功能和语言增强:
  • Switch 表达式 (预览):Switch 可以作为一种表达式使用,并且支持多标签模式:
    int numLetters = switch (day) {
        case MONDAY, FRIDAY, SUNDAY -> 6;
        case TUESDAY                -> 7;
        default                     -> {
            var len = day.toString().length();
            yield len;
        }
    };
  • Shenandoah GC (实验性):一种低暂停时间垃圾回收器。
  • JVM 常量 API:用于描述常量池中的常量。
  • 字符串增强:新增了 transform 方法和 indent 方法,以简化字符串处理。
Java 13 (2019年9月)

Java 13 带来了一些语言和平台级别的改进:
  • 文本块 (预览):多行字符串字面量,可以保留字符串的格式和内容的可读性,使用 """ 包围:
    String json = """
    {
        "name": "John",
        "age": 30
    }
    """;
  • Switch 表达式的改进:继续作为预览特性存在,增加了更好的匹配控制和语法。
  • 动态 CDS 档案:增强了类数据共享功能,允许在运行时为未加载的类动态生成共享档案。
  • ZGC 改进:引入未使用的内存回收和可扩展的内存限制。
Java 14 (2020年3月)

Java 14 继续增加了一些实验性功能:
  • Switch 表达式 (正式引入):作为 Java 标准的一部分引入,消除了多标签的重复代码。
  • 记录 (Records) (预览):用于定义不可变数据载体类,简化数据类的编写:
    public record Point(int x, int y) {}
  • instanceof 模式匹配 (预览):改进 instanceof 操作符,减少显式类型转换:
    if (obj instanceof String s) {
        System.out.println(s.length());
    }
  • NullPointerException 改进:增强了 NullPointerException 的诊断信息,提供更明确的错误原因。
  • Foreign-Memory Access API (孵化器):实验性的 API,用于更高效地访问和操作非 Java 堆内存。
Java 15 (2020年9月)

Java 15 引入了多个新特性:
  • 文本块 (正式引入):文本块成为 Java 语言的一部分,正式支持多行字符串。
  • 密封类 (预览):密封类允许开发者控制哪个类可以扩展或实现它,从而增强了类的封装性:
    public abstract sealed class Shape
        permits Circle, Square {
    }
  • ZGC 成为生产可用的特性:ZGC 垃圾回收器从实验性状态中移除,成为正式的生产可用垃圾回收器。
  • Records (第二预览):进一步改进和修复了 Records 的设计。
  • instanceof 模式匹配 (第二预览):继续优化和扩展模式匹配的使用。
  • Hidden 类:用于字节码生成的内部类的定义,帮助提高动态代理类的性能。
Java 16 (2021年3月)

Java 16 引入了多个语言级和平台级的增强:
  • Records (正式引入):记录类作为 Java 语言的一部分,正式推出,简化了不可变数据类的定义。
  • instanceof 模式匹配 (正式引入):instanceof 模式匹配正式成为 Java 语言的一部分。
  • 密封类 (第二预览):密封类得到进一步增强,允许更多的使用场景。
  • ZGC 并行垃圾收集:ZGC 的垃圾回收并行化,使其性能进一步提升。
  • 强封闭性 JDK:JDK 模块进一步封闭,不允许不规范的访问。
  • 外部函数和内存 API (孵化器):提供更简洁和安全的 API 用于与非 Java 堆内存交互。
Java 17 (2021年9月)

Java 17 是另一个长期支持版本 (LTS),带来了稳定的语言特性和平台改进:
  • 密封类 (正式引入):密封类正式成为 Java 语言的一部分,允许开发者限制子类的类型。
  • 模式匹配 for switch (预览):在 switch 语句中引入模式匹配,使得代码更为简洁和灵活。
  • 移除 RMI 激活:RMI 激活机制被移除,反映了这一远程调用技术的使用减少。
  • 加强的 JDK 安全性:通过封闭内部 API 和引入更严格的访问控制来加强安全性。
  • 更强大的 G1 GC:G1 垃圾回收器进一步优化,提高了并发性能和内存管理能力。
  • 外部函数和内存 API (第二孵化器):进一步改进了该 API,使其在与本地代码交互时更加稳定和易用。

这些新特性不仅使得 Java 更加现代化,也提升了开发效率和运行时性能,为开发者提供了更强大、灵活的工具链。
Java 17 到 Java 21 之间的版本引入了多个新特性和改进。以下是这些版本的详细介绍:Java 18 (2022年3月)

Java 18 是一个功能性版本,带来了一些新功能和改进:
  • UTF-8 默认字符集:Java 18 将 UTF-8 设置为默认字符集,这意味着无论在何种平台上,所有的字符编码和解码操作都会使用 UTF-8。
  • 简单 Web 服务器:引入了一个简单的命令行 Web 服务器,用于静态文件的开发和测试。这对于快速启动一个 Web 服务器以托管静态内容非常有用:
    jwebserver
  • 代码段 API (孵化器):Java 引入了代码段 API (Code Snippets API),用于表示和操作代码段,这对于 IDE 和文档生成工具非常有用。
  • 外部函数和内存 API (第二孵化器):继续改进了用于与非 Java 堆内存交互的 API。
  • 向量 API (第三孵化器):向量 API 允许使用矢量计算优化代码,特别是对于需要高性能计算的应用程序。
Java 19 (2022年9月)

Java 19 继续增强现有功能,并引入了一些新的实验性特性:
  • 虚拟线程 (预览):虚拟线程(Project Loom)是 Java 并发模型的一项重大改进,它允许开发者创建大量的轻量级线程,以简化并发编程。虚拟线程是以非常低的成本管理的,这使得大规模并发更加高效。
  • 结构化并发 (预览):这种 API 允许使用结构化的方式来处理多个线程的生命周期,使并发代码更加清晰和容易管理。
  • 模式匹配 for switch (第二预览):在 switch 语句中进一步增强了模式匹配,允许更复杂和强大的匹配逻辑。
  • 外部函数和内存 API (第三孵化器):继续发展和改进该 API,以更好地支持与本地代码和内存的交互。
  • 向量 API (第四孵化器):进一步增强和优化了向量 API,用于高性能计算。
Java 20 (2023年3月)

Java 20 继续增强之前的预览和孵化器功能,并引入了一些新的实验性功能:
  • 虚拟线程 (第二预览):虚拟线程得到进一步的改进,增加了更多的功能,使得并发编程更为简便和高效。
  • 结构化并发 (第二预览):结构化并发 API 进一步增强,提供更好的工具来管理并发任务。
  • 记录模式 (预览):记录模式(Record Patterns)允许在模式匹配中使用记录的组件来解构对象,这使得处理复杂数据结构变得更容易:
    record Point(int x, int y) {}

    Object obj = new Point(3, 4);
    if (obj instanceof Point(int x, int y)) {
        System.out.println("x = " + x + ", y = " + y);
    }
  • 模式匹配 for switch (第三预览):再次改进模式匹配 for switch 的功能,使得匹配逻辑更为灵活和强大。
  • 向量 API (第五孵化器):进一步增强向量 API,支持更多的数据类型和操作。
  • 外部函数和内存 API (第四孵化器):继续改进该 API,以增强与本地代码的集成。
Java 21 (2023年9月)

Java 21 是一个长期支持版本 (LTS),并且引入了许多新特性和改进:
  • 虚拟线程 (正式引入):虚拟线程正式成为 Java 的一部分,极大地简化了大规模并发应用的开发,允许以更低的开销创建和管理线程。
  • 结构化并发 (正式引入):结构化并发 API 也成为 Java 的一部分,为并发任务提供了更直观和安全的管理方式。
  • 记录模式 (第二预览):记录模式继续作为预览功能存在,进一步增强了解构记录对象的能力。
  • 模式匹配 for switch (正式引入):模式匹配 for switch 语句正式成为 Java 的一部分,极大地提升了 switch 语句的表达能力和灵活性。
  • 外部函数和内存 API (第五孵化器):继续改进该 API,使其更为稳定和高效,适用于更多的场景。
  • 向量 API (正式引入):向量 API 也正式成为 Java 的一部分,为需要高性能计算的应用程序提供了强大的工具。
  • 字符串模板 (预览):引入了字符串模板(String Templates),允许在字符串中嵌入表达式并在运行时计算其值,这种模板机制使得字符串处理更加简洁和灵活:
    String name = "world";
    String message = STR."Hello, \{name}!";
  • 新垃圾回收器 (ZGC 和 G1 增强):进一步优化了 ZGC 和 G1 垃圾回收器的性能和可伸缩性,使其更适合大规模应用。

这些版本的特性增强了 Java 的并发能力、模式匹配灵活性、与本地代码的集成以及高性能计算能力,为开发者提供了更强大的工具来应对现代应用程序的需求。
在Java的开发过程中,"孵化器"和"预览"是两个重要的概念,它们表示新特性在正式引入Java语言或平台之前的不同阶段。1. 孵化器 (Incubator)

孵化器是Java平台引入新API或新功能的早期阶段。在这个阶段,特性仍在积极开发和实验中。孵化器功能允许开发者提前体验和测试这些新功能,并且提供反馈,从而帮助开发者社区决定是否以及如何在未来的Java版本中正式引入这些特性。
  • 特点
    • API 或功能可能会在未来版本中大幅度更改。
    • 该功能可能不会进入最终版本,或者会以不同的形式出现。
    • 使用孵化器功能的代码在未来可能需要进行调整或重构。
  • 示例
    • 外部函数和内存 API (Incubator):这是一个早期的API,允许Java程序更安全和高效地与非Java内存进行交互。因为它是一个孵化器功能,所以API的设计可能会在未来版本中发生变化。
2. 预览 (Preview)

预览阶段是在孵化器之后的一个开发阶段。在预览阶段,特性已经得到了更多的开发和稳定,但仍然在收集用户反馈,可能会进行一些微调。预览特性可以在实际生产环境中进行测试,但通常需要通过启用特定的编译器选项来使用。
  • 特点
    • 预览特性在发布时已经非常接近于最终设计。
    • 仍有可能进行小幅修改或调整。
    • 特性最终可能会成为标准部分,也可能被进一步推迟或修改。
    • 开发者可以在实际项目中使用预览特性,以便为其发布提供反馈。
  • 示例
    • Switch 表达式 (Preview):Java 12 中首次引入了Switch表达式的预览版,它允许在switch语句中返回值并使用更简洁的语法。随着社区的反馈,这个功能在后续版本中得到了完善,并最终在Java 14中成为正式特性。
总结
  • 孵化器:是开发者探索新API或功能的早期阶段,提供实验性的功能。
  • 预览:是更接近最终版本的阶段,开发者可以在实际项目中测试这些功能,并提供反馈,以便在正式发布之前进行微调。

通过这种多阶段引入新特性的方式,Java开发团队能够确保新功能的稳定性和实用性,同时与开发者社区保持紧密互动。
回复

使用道具 举报

🔗
 楼主| Cabbage1123 2024-9-3 01:44:14 | 只看该作者
全局:
本帖最后由 Cabbage1123 于 2024-9-2 10:47 编辑

2024-09-02
突发奇想,要不开个repo每天post一个面经solution好了,虽然不找工作但是地里面经这么多。。。我会给我看过的面经加米~谢谢提供面经的大哥大姐们先
search url:
https://www.1point3acres.com/bbs ... 11&orderby=dateline
Update:看起来1point3acre的前端不太行,一个url里带query的链接点开,前端居然不能进行相关的查找。。。

面经范围:
1. 工作类别:全职
2. 相关工作经验范围:1-3年
3. 应届or在职跳槽:在职跳槽
4. 工作职位类别:码农类general

回复

使用道具 举报

🔗
 楼主| Cabbage1123 2024-9-3 03:09:37 来自APP | 只看该作者
全局:
本帖最后由 Cabbage1123 于 2024-9-2 12:15 编辑

2024-09-02
Chatgpt真的好厉害,我愿称之为程序员最好的心理咨询师。。。
今天的心理咨询内容:


补充内容 (2024-09-03 03:09 +08:00):
Q:Java为啥都是引用啊,烦死了,Rust就不是,Rust是生命周期
A:
Java 的设计哲学中,引用(reference)是一种核心概念。Java 中所有对象都是通过引用来操作的,而不是直接操作对象本身。这样设计的原因有以下几个方面:
  • 内存管理:Java 使用垃圾回收机制(Garbage Collection, GC)来自动管理内存。这种机制依赖于引用来追踪对象的生命周期,避免内存泄漏。通过引用,Java 可以轻松地确定哪些对象不再被使用,从而释放内存。
  • 简化编程模型:引用使得Java开发者不需要手动管理内存的分配和释放。这大大降低了内存管理的复杂性,减少了程序员犯错误的机会。
  • 对象共享:通过引用,可以在多个地方共享同一个对象。这样修改对象的一部分可以反映到所有持有这个引用的地方,减少了数据复制的开销和不一致性。

与之相比,Rust 的生命周期(lifetime)机制提供了对内存管理的更细粒度的控制。在 Rust 中,编译器通过生命周期和借用(borrowing)规则确保对象的内存安全,这意味着程序员需要显式地管理对象的所有权(ownership)和生命周期。这使得 Rust 在内存管理上更为高效,同时也更加复杂,因为程序员需要手动处理所有权和生命周期。总结
  • Java 的引用简化了内存管理和对象操作,但缺乏对内存使用的精细控制。
  • Rust 的生命周期机制提供了更高效的内存管理,但要求程序员对内存生命周期有更深入的理解和管理。

你觉得 Java 的引用机制有哪些特定的使用场景让你感到烦恼吗?也许我们可以深入探讨一些具体的问题或优化方法。

补充内容 (2024-09-03 03:14 +08:00):

Q:非常不顺手,比如说
public class WordCount {

    final ForkJoinPool pool = ForkJoinPool.commonPool();

    private static HashMap<String, Integer> countByString(String str) {
        var map = new HashMap<String, Integer>();
        StringTokenizer tokenizer = new StringTokenizer(str);
        while(tokenizer.hasMoreTokens()) {
            var word = tokenizer.nextToken();
            incKey(word, map, 1);
        }
        return map;
    }

    private static void incKey(String key, HashMap<String, Integer> map, Integer n) {
        if(map.containsKey(key)) {
            map.put(key, map.get(key) + n);
        } else {
            map.put(key, n);
        }
    }
}

这里的countByString声明了map,然后传到incKey里居然不返回,从程序员的角度来讲我就得考虑,map其实改变值了,但是为什么没有返回。这样就很难懂。而且这个incKey在当前的类里可能会被多次调用,在不同的context下,map的意思也不一样,真的挺难懂的


A:
你提到的问题确实是Java引用机制带来的典型挑战。由于Java中对象是通过引用传递的,因此当你在方法中对对象(例如HashMap)进行修改时,原始对象也会被修改,这可能会让代码的行为变得不那么直观。
在Rust中,由于更严格的所有权和借用规则,这种问题比较少见,因为你必须明确地处理对象的所有权和生命周期,这使得代码的意图更清晰。


如何改进Java代码的可读性
  • 明确方法行为:为了让代码更容易理解,可以通过方法命名和文档注释明确方法的行为。例如,incKey方法可以命名为updateOrInsertKey,这样名称就暗示了它会修改传入的map。
  • 返回修改后的对象:尽管Java中不需要返回修改后的对象,但你可以选择让方法返回它修改的对象。虽然这是一个冗余的操作,但可以增加代码的可读性。例如:java复制代码
    private static HashMap<String, Integer> incKey(String key, HashMap<String, Integer> map, Integer n) {
        if(map.containsKey(key)) {
            map.put(key, map.get(key) + n);
        } else {
            map.put(key, n);
        }
        return map;
    }

    这样调用者就可以直接接收到修改后的map,明确知道它被改变了。
  • 使用不可变对象:在某些情况下,可以使用不可变对象来避免这种困惑。Guava或其他库提供的不可变集合可以帮助确保集合不会在方法中被意外修改。
  • 避免全局状态:如果可能,避免在方法中修改传入的全局或共享对象,而是尽量返回新的对象。这种方式可以减少副作用,让代码的行为更加清晰。


Rust 的对比

在Rust中,你必须显式地将可变引用传递给方法,这使得程序员很容易看出哪些对象会被修改。此外,Rust 的编译器会在编译期检查所有权和借用规则,确保对象的生命周期和修改行为是明确和安全的。
总之,虽然Java的引用机制有其便利之处,但在编写复杂逻辑时,特别是在方法中修改传入对象时,明确代码意图和行为对代码的可维护性至关重要。如果这些问题对你造成了困扰,可以考虑通过更清晰的代码结构和注释来缓解这些问题。

补充内容 (2024-09-03 03:26 +08:00):

Q:我其实不太明白,如果Java全部都是引用的话,使用引用计数,在多线程的情况下怎么垃圾回收啊,不会造成死锁吗?
A:
Java 的垃圾回收机制(Garbage Collection, GC)并不依赖于引用计数。相反,Java使用一种基于可达性分析(reachability analysis)的垃圾回收算法,这使得它能够在多线程环境中更有效地管理内存,而不容易导致死锁。Java 垃圾回收机制的工作原理
  • 可达性分析:Java 的垃圾回收器通过可达性分析来决定对象是否可以被回收。简单来说,从一组称为“根”(roots)的对象开始,垃圾回收器遍历所有的对象引用。如果某个对象无法通过任何引用路径从根对象到达,它就会被标记为可回收。这意味着,即使一个对象有多个引用,只要它不再可达,垃圾回收器就会将其回收。
  • 多线程环境:在多线程环境下,Java 的垃圾回收器可以安全地操作,因为它会“暂停”所有应用线程(Stop-The-World)来进行内存分析和回收。这意味着,在垃圾回收过程中,不会有其他线程在修改对象引用,这样避免了竞争条件(race condition)。
  • 死锁避免:由于垃圾回收器并不依赖引用计数,所以不必担心引用计数在多线程环境下增加或减少导致的不一致性问题,从而避免了可能的死锁。引用计数法容易在循环引用的情况下导致内存泄漏,而Java的可达性分析则避免了这个问题。
引用计数 vs. 可达性分析
  • 引用计数:这是一个简单的垃圾回收策略,通过维护每个对象的引用计数来管理对象的生命周期。当计数变为零时,对象就可以被回收。然而,这种方法在处理循环引用时会失效,而且在多线程环境下,增加和减少引用计数的操作需要加锁,可能会导致性能问题和死锁。
  • 可达性分析:这是Java垃圾回收器使用的方法。它更复杂,但也更强大,特别是在多线程环境下。它能够正确处理循环引用,并且在大多数现代GC实现中,它们通过优化减少了对应用线程的影响。
Java 的垃圾回收器类型

Java提供了多种垃圾回收器,例如:
  • Serial GC:适用于单线程应用,效率高但不适用于多线程应用。
  • Parallel GC:适用于多核系统,通过并行垃圾回收来提高性能。
  • G1 GC:设计用于大内存多线程应用,具有预测性暂停时间的特点。
  • ZGC 和 Shenandoah:超低暂停时间的垃圾回收器,适用于非常高响应需求的应用。

这些GC算法都不依赖引用计数,因此在多线程环境下不会因为引用计数导致死锁问题。总结

Java 在多线程环境中使用可达性分析而非引用计数来进行垃圾回收。这种方式避免了引用计数在多线程环境下的复杂性和死锁风险,确保了Java应用在内存管理上的安全性和稳定性。


Q:如果是 Stop-The-World 了,万一程序 crash 了,咋办???
A:当Java的垃圾回收器执行“Stop-The-World” (STW) 操作时,它会暂停所有应用线程以进行内存管理操作。然而,如果在STW期间程序发生崩溃,这确实可能导致问题。
下面是一些应对和防范措施:1. 防止崩溃的设计
  • 使用稳定的GC算法:选择经过充分测试的垃圾回收器,如G1 GC、ZGC、或Shenandoah GC,这些GC算法经过优化,能够处理高负载和复杂的内存管理情况,减少崩溃的可能性。
  • 减少STW的时间:现代GC算法(如G1 GC、ZGC)专注于减少STW暂停的时间,从而降低由于长时间暂停导致问题的风险。它们通过分阶段或并行的方式执行垃圾回收,尽可能缩短STW事件。
2. 容错机制
  • 定期快照和备份:在关键应用中,定期保存应用状态的快照或进行数据备份可以在崩溃后进行恢复,减少数据丢失和停机时间。
  • 冗余设计:使用集群或冗余系统设计(如分布式系统中的副本)可以确保在某个实例崩溃时,其他实例能够接管任务,从而避免整个系统宕机。
3. Crash Handling机制
  • 操作系统层面的保护:操作系统可以捕捉程序崩溃事件(如SIGSEGV信号),触发预定义的恢复或重启流程。对于关键应用,系统可以配置为自动重启崩溃的Java进程。
  • JVM 崩溃日志:Java虚拟机在崩溃时会生成一个称为“错误日志”(通常是hs_err_pid.log)的文件。这个日志文件包含崩溃时的详细信息(例如线程状态、内存堆栈、GC状态等),有助于分析和修复问题。
4. 监控和预警
  • 实时监控:使用监控工具(如Prometheus、Grafana)实时监控JVM的运行状态,包括内存使用情况、GC暂停时间等。当检测到异常或暂停时间过长时,可以触发警报或自动化处理机制。
  • 自动化恢复:结合监控系统,可以设计自动化的恢复机制,例如检测到长时间GC后自动重启JVM实例,或通过容器化(如Kubernetes)自动重新调度和部署应用。
5. 调优GC参数
  • GC参数调优:根据应用的特定需求和运行环境,调整JVM的GC参数,以减少STW事件的频率和持续时间。常见的调优参数包括堆大小、分代大小、GC线程数等。


总结

尽管STW机制在Java垃圾回收中是必要的,但通过选择合适的GC算法、调优参数、设计冗余和容错系统、以及实时监控,可以大大降低程序在STW期间崩溃的风险。即便发生崩溃,合理的恢复机制和日志分析可以帮助迅速定位问题并恢复系统运行。




Q:这样处理不会增加 Java 应用的复杂度吗?后期人员就很难维护了?
A:是的,引入这些防范措施确实会增加Java应用的复杂度,尤其是在大规模、高可用性系统中。复杂性带来的后期维护难度是一个需要权衡的现实问题。以下是如何在保持系统健壮性的同时,尽量减少复杂性和维护难度的一些方法:1. 合理选择GC和优化参数
  • 默认GC:对于大多数应用场景,JVM的默认GC(例如G1 GC)已经足够稳定和高效,且经过大量测试。避免过度优化GC参数,除非有特定需求,否则默认配置通常可以提供一个良好的平衡点。
  • 适当的调优:如果需要调优GC参数,尽量使用官方推荐的参数调优指南,并记录每次调整的目的和效果。这有助于团队成员理解为什么做出这些选择。
2. 使用现有工具和框架
  • 容器化和编排:使用如Kubernetes这样的容器编排工具,可以简化应用的管理、部署和扩展。它们提供了自动重启、负载均衡和自愈能力,从而减少了手动管理和故障处理的复杂性。
  • 监控平台:使用成熟的监控工具(如Prometheus、Grafana、New Relic等),而不是自己开发监控系统。现成的工具通常有良好的社区支持和文档,可以减少维护成本。
3. 代码和配置文档化
  • 文档记录:将GC参数配置、监控设置、故障处理流程等文档化。这些文档应包括配置的理由、期望的效果、可能的风险等,帮助新成员迅速上手。
  • 自动化文档生成:可以使用自动化工具生成和维护文档,例如通过配置管理工具自动记录配置变更,或使用注释和代码注释生成工具来生成代码文档。
4. 模块化设计
  • 分离关注点:将不同的功能模块化,例如将监控和日志收集、异常处理等功能与核心业务逻辑分离开来。这种设计可以降低单个模块的复杂性,同时方便团队中的不同成员专注于各自的领域。
  • 使用中间件:利用现有的中间件(如AOP(面向切面编程)框架)来处理横切关注点(如日志、监控、异常处理),减少对核心代码的侵入性修改。
5. 定期代码审查和技术债务管理
  • 代码审查:通过代码审查来确保GC参数配置、监控工具的使用和其他复杂设置是合理的,并避免过度复杂化的解决方案。
  • 管理技术债务:识别和记录技术债务,并定期评估是否需要偿还。技术债务可以包括过度复杂的GC配置、冗长的恢复机制等。通过定期清理和优化代码库,可以减少长期维护的负担。
6. 培训和知识共享
  • 内部培训:定期举办内部培训,让团队成员理解和熟悉GC机制、监控系统和容器化管理工具。这样可以减少因复杂性带来的沟通障碍。
  • 知识共享平台:利用知识共享平台(如Confluence、Notion等)集中存储和共享关键的系统设计文档、问题解决方案和经验总结。
7. 利用云服务
  • 托管服务:现代云服务提供商(如AWS、GCP、Azure)提供了托管的JVM优化和监控服务,这些服务通常经过高度优化,可以显著降低管理和维护的复杂性。
  • 弹性伸缩:利用云服务的弹性伸缩能力来自动调整资源配置,从而减少手动管理GC带来的复杂性。
总结

虽然为了提高应用的健壮性和可靠性,添加一些机制和配置不可避免地会增加系统的复杂性,但通过合理的架构设计、模块化、使用成熟的工具和框架,以及充分的文档化和知识共享,能够在不显著增加维护难度的情况下,保持系统的可维护性和可扩展性。这种平衡是成功软件工程的重要组成部分,特别是在需要长期维护的大型系统中。


Q:既然要做的事情这么多,那为啥不用 Rust 开发应用啊?????
A:这是一个很好的问题!Rust和Java各有优缺点,选择哪种语言取决于具体的应用场景、团队的技术栈和项目需求。让我们详细对比一下两者:1. 内存安全和性能
  • Rust
    • 内存安全:Rust 通过所有权机制和借用检查器在编译时确保内存安全,消除了数据竞争和空指针引用等常见问题,特别适合开发高性能、高并发的应用。
    • 性能:Rust 的性能接近于C/C++,因为它不依赖于垃圾回收器(GC),而是通过精细控制内存分配来实现高效运行。
  • Java
    • 垃圾回收:Java依赖GC来管理内存,这虽然减少了手动内存管理的负担,但在某些高性能应用中可能带来一些开销和不确定性(如STW事件)。
    • 性能:虽然Java经过多年的优化,在许多场景下性能非常出色,但在一些需要极致性能的场景(如系统编程、嵌入式开发)中,Java可能不如Rust。
2. 开发体验和生态系统
  • Rust
    • 语言学习曲线:Rust的所有权和生命周期概念复杂度较高,开发人员需要投入较多的学习时间。这对熟悉垃圾回收语言(如Java、Python)的开发者来说是一个挑战。
    • 生态系统:Rust的生态系统在快速增长,尤其在系统编程、WebAssembly和嵌入式开发方面已经很成熟。但在企业级应用开发领域,生态相对Java还不够完备。
  • Java
    • 成熟的生态系统:Java拥有丰富的类库、工具和框架,如Spring、Hibernate等,在企业应用、Web开发、数据处理等领域非常成熟。开发者可以利用这些现成的工具快速构建复杂系统。
    • 开发效率:Java的垃圾回收机制和自动内存管理简化了开发人员的任务,降低了内存管理的复杂度,从而提高了开发效率。
3. 团队和社区支持
  • Rust
    • 社区:Rust社区活跃、包容,社区贡献非常积极。特别是在开源项目中,Rust有很多优秀的库和工具。
    • 招聘与人才:由于Rust是相对较新的语言,熟练掌握Rust的开发人员相对稀缺,可能增加招聘难度。
  • Java
    • 庞大的开发者社区:Java拥有全球最大的开发者社区之一,丰富的在线资源、教程、论坛和文档。对于需要快速扩展团队的企业来说,Java开发人员更容易找到。
    • 企业级支持:Java被许多大企业广泛使用,成熟的技术支持和商业服务可帮助企业解决遇到的问题。
4. 应用场景
  • Rust
    • 适合需要高性能、高并发的应用,如系统编程、网络服务、嵌入式开发、区块链等。
    • 在安全性和性能至关重要的领域,如金融系统、高频交易平台或实时数据处理应用,Rust是一个理想的选择。
  • Java
    • 适合企业级应用、Web开发、大数据处理、分布式系统等需要成熟框架和工具支持的场景。
    • Java 的跨平台特性(通过JVM)和丰富的企业级库使其成为开发大型企业应用的首选。
5. 开发效率 vs. 性能
  • Rust:如果你愿意为更高的性能和安全性付出学习和开发时间的成本,Rust是一个出色的选择。它能够避免很多运行时错误,在高性能要求的场景中表现优异。
  • Java:如果开发效率、可维护性和现有生态系统的利用对项目更为重要,Java可能是更好的选择。尤其在团队规模大、项目复杂的情况下,Java的成熟度和稳定性是巨大的优势。
总结

选择Rust还是Java,取决于项目的需求和团队的技术背景。Rust提供了更高的性能和内存安全性,但需要更深的技术理解和时间投入。Java提供了更高的开发效率、丰富的工具和广泛的社区支持,适合快速开发和维护复杂的企业级应用。
如果你的应用对性能和内存安全有极高的要求,且团队有能力应对Rust的复杂性,那么Rust是一个非常好的选择。相反,如果你需要快速开发、使用现有的工具和框架,Java仍然是许多场景下的最佳选择。


Q:你觉得开发效率和维护成本哪个更重要呢?Java 虽然开发效率很高,但是一不小心就 NullPointerException 和 死锁 了,这种不经过测试都找不出来der?
A:开发效率和维护成本的权衡是一个复杂的问题,通常取决于项目的规模、生命周期、团队的技术能力,以及系统的稳定性要求。让我们从几个方面来探讨这个问题。1. 开发效率 vs. 维护成本
  • 开发效率
    • 开发效率指的是开发人员在规定时间内能够完成多少工作。高效的开发意味着更快的交付、更短的上市时间和更快的反馈循环。Java由于其丰富的生态系统和工具支持,在这方面非常强大。
    • 然而,高开发效率有时会带来较高的技术债务。如果在开发过程中没有足够的关注代码质量和架构设计,后期的维护成本可能会急剧上升。
  • 维护成本
    • 维护成本包括修复bug、优化性能、扩展功能以及保持代码质量的成本。Java中的NullPointerException、死锁等问题确实可能在开发过程中被忽视,并在后期暴露出来。
    • 当维护成本过高时,即使最初的开发效率很高,项目整体的生命周期成本也会显著增加,甚至可能导致项目不可持续。
2. Java的陷阱:NullPointerException 和死锁
  • NullPointerException
    • Java的NullPointerException是一个常见的运行时错误,通常由未正确处理的空引用引起。在开发时很容易忽视这种问题,尤其是在代码复杂、依赖关系多的情况下。
    • 解决方案:可以通过使用更严格的空值处理机制(如Java的Optional类)和引入静态分析工具(如FindBugs、SpotBugs)来捕获潜在的NullPointerException。此外,良好的测试覆盖率也有助于在开发过程中发现这些问题。
  • 死锁
    • 死锁是多线程编程中的一个难以检测和复现的问题,尤其是在复杂的并发代码中。Java的并发模型虽然强大,但容易出现这种陷阱。
    • 解决方案:使用更高层的并发工具(如Java的java.util.concurrent包)来减少手动同步的复杂性,或者使用不变性和无锁编程来避免死锁。同时,可以通过设计评审、代码审查和工具(如动态死锁检测器)来减少发生死锁的风险。
3. Rust的优势:编译期安全性
  • Rust的编译器强制执行严格的所有权、借用和生命周期规则,确保了内存安全和并发安全。这意味着许多在Java中依赖于测试和运行时检查才能发现的问题,在Rust中会在编译时被发现。
  • 编译期安全性:Rust消除了空指针和数据竞争等问题,从而大幅减少了维护成本。尽管Rust的开发效率可能不如Java,但它的设计目标是“编写一次,正确运行”,从而降低了后期维护成本。
4. 实际的权衡
  • 小型或短期项目:如果项目生命周期短、变化频繁,或者需求变化快,开发效率可能更重要。Java凭借其成熟的生态系统和丰富的库,可以快速交付功能并适应变化。
  • 大型或长期项目:对于生命周期长、复杂性高的项目,维护成本通常更为重要。即使初期的开发效率较低,通过Rust或更严谨的Java开发方式降低后期维护成本,往往更符合项目的长期利益。
  • 团队能力和文化:如果团队中有较强的工程能力,能够有效避免Java中的常见陷阱,并且对代码质量有高度的关注,那么Java可以在高效开发和可维护性之间找到平衡。
5. 总结
  • 开发效率 vs. 维护成本:两者同等重要,但在不同的项目中会有不同的优先级。短期项目往往更注重开发效率,而长期项目更关注维护成本。
  • 选择适合的工具:如果项目需要高度可靠性且长期维护,Rust可能是更好的选择。如果项目需要快速迭代和交付,Java的高开发效率是一个强大的优势。
  • 提高代码质量:无论使用哪种语言,通过更好的代码审查、测试、静态分析工具和设计模式,都可以减少潜在问题,提高代码的可维护性,从而在开发效率和维护成本之间找到更好的平衡点。

在实际工作中,这种权衡通常是根据具体情况做出的,需要综合考虑项目特点、团队经验和业务需求。


好的,这些回答我很满意,继续学 Java 了。。。



回复

使用道具 举报

🔗
 楼主| Cabbage1123 2024-9-11 14:00:20 | 只看该作者
全局:
2024-09-10
LC 每日一题+        Integer to English Words + Minimum Window Substring

今天在看 distributed cache 的时候发现了这个!https://github.com/facebook/rocksdb/wiki 开个新坑~
回复

使用道具 举报

🔗
 楼主| Cabbage1123 2024-12-30 15:43:54 | 只看该作者
全局:
哈哈又是好久不见了,汇报下近况:
工作:
1. 成功转组!从AWS转到PXT!不写Rust要去做全栈了哈哈~还是想多写点代码吧,就,与其每天埋头干苦力活不如停下来想想如何提升软实力+写出漂亮优雅的代码。另一方面是组里的代码现在已经扭曲到了很难看懂的地步。。。。转组必然还是很不舍的,但已经很期待以后的工作和生活啦~希望career path可以少一些manual work多一些soft skills+coding hhh

生活:
1. 平淡无奇,除了圣诞节去爬了个Joffree lake但是没有上冰川(有点可惜)
2. 给房间做了大扫除,买了很多书!很兴奋!

人际:
1. 交了一些朋友,很多观点都很有启发性~开心~
2. 对象的签证搞出岔子导致没办法回国见父母!结婚计划遥遥无期。。。。生气(一个成年人居然可以粗心到这种地步)
3. 帮助一个朋友准备面试复习资料,她拿到了offer!开心!

鉴于今年这个学习记录贴的良好记录情况(指2024年1-9月均保持不错的学习记录,10月和11月我也有不定期学习打卡,但是是在一个小群里哈哈以后也可能不在那个群打卡了),我今年买了一个新本子,希望通过手写增加更多的内容。这个帖子可能不会经常更新啦哈哈。不过我可能会用这个贴子继续分享一些我看到的帖子或者其他资料(还记得大明湖畔的面经crack坑嘛哈哈,以后会写的~)

还是很感谢这个帖子陪了我今年大半年的时光,笔芯~
回复

使用道具 举报

全局:
有刷题群吗?
回复

使用道具 举报

无效楼层,该帖已经被删除
全局:
Cabbage1123 发表于 2025-1-4 02:45
我没加刷题群23333,有的话拉我一下~

你建一个吧,一起刷,不懂的讨论讨论,效率应该更高吧?
回复

使用道具 举报

🔗
hoinky 2025-1-7 09:53:42 | 只看该作者
全局:
lz你好 想问下cpen 522难度如何呀 给分好吗?
回复

使用道具 举报

🔗
 楼主| Cabbage1123 2025-1-7 10:15:21 来自APP | 只看该作者
全局:
hoinky 发表于 2025-01-06 17:53:42
lz你好 想问下cpen 522难度如何呀 给分好吗?
我选的是UBC 暑期的CPEN 522,具体内容包括4次小测试+平时每周阅读批注+paper presentation+4次作业,总共100分我最后拿了92(还是90我忘了)这门课的作业主要用C++~我个人觉得不难因为只需要presentation+好好做阅读的批注就能拿到将近50分吧。比较tricky 的地方在于作业,虽然我在这门课作业上的总体投入时间远小于cpen 502(就是那个写robocode 做ml 的课)这门课只要认真对待是可以考上80分的,但是我其他同学都说CPEN522挺难的……

如果你是转码重点放在找工作的话我还是推荐不要选1.语言是C++但是这里找工作貌似Java更吃香 2. 几次quiz 考的内容基于老师的ppt 可能会渗入一点点,但是不多,这要求你好好看认真复习ppt 如果你想水过的话可能会非常不容易 3.阅读任务虽然不多但是那个评测系统的打分感觉还挺奇怪的,得认真写注释而且要写很多才能得满分💯

如果你不是转码的而且没有非常非常重的课业压力和工作压力,那你可以选,这门课作业的debug 还挺好玩的,能了解一点点🤏software verification 的知识而且我那个时候的老师和助教人都还不错(具体体现在好多人作业3不会写想推迟ddl 助教和老师就给推了)

这门课当时每周大概花我3-4小时?不过我们小组作业的同学3个人里俩都是本科就学cs 的哈哈,这门课比编译原理和操作系统简单多啦~难度的话讲道理应该还要比计算机网络稍简单~

如果你真的想选水课其实可以看看一些ml 的课,祝好~

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表