GitHub 结束独立运营?!
老实说,看到消息的时候我还以为自己没睡醒。
自从 2018 年微软豪掷 75 亿美元把 GitHub 收入囊中,坊间就猜它迟早要“收编”。但这些年 GitHub 一直端着“独立运营”的人设,搞得大家差点忘了它早就是“微软家的崽”。
结果事情发生得猝不及防。
GitHub CEO Thomas Dohmke 今天突然宣布辞职,并透露 GitHub 将整体并入微软新成立的CoreAI。
从目前的消息来看,Thomas Dohmke 将会留任 GitHub CEO 直到年底完成交接。然后跑路创业。微软则是连新 CEO 都不找了。
这下独立的 GitHub没了!CEO也没了!
直接把开发者圈炸开了锅。
当初微软收购 GitHub,有人觉得这笔交易是微软拥抱“开源”的标志,但微软砸了 75 亿美元收购 GitHub,就为了好心为大家提供一个代码托管平台?
反正鸭鸭没信过。
不过 7 年以来,GitHub一直保持相对独立运作,这波“温水煮青蛙”,确实让不少人放松了警惕。也让 GitHub 攒下了 10 亿+代码库、1.5 亿+ 开发者的恐怖家底。
没想到独立只是缓兵之计,微软或许只是在放长线钓大鱼。
推动这次大整合的幕后操盘手,微软 CoreAI 团队的负责人 Jay Parikh,早前就曾放出豪言:“我希望我们的平台,能变成所有公司和组织的 AI 智能体工厂。”
GitHub 的未来,或许要彻底“微软化”,成为微软专属的“AI智能体流水线”。
微软这波操作,也赤裸裸展示了 AI 竞争的核心——数据!数据!还是数据! 10 亿代码库,是训练 AI 模型、构建智能体的无价之矿。“得数据者得 AI 天下”,微软这步棋,又快又狠。
收获了 GitHub 上 10 亿个代码仓库之后,微软将“弹药充足”地投入接下来的 AI 竞争。
GitHub的“独立时代”猝然落幕,开发者们,也要告别 GitHub 这块曾经的“乐土”,转而重新适应这个新世界。
今天我们来看一个 Java 字节跳动后端社招一面。
为什么要有线程池,线程池的作用是什么?
线程池是一种池化技术,用于预先创建并管理一组线程,避免频繁创建和销毁线程的开销,提高性能和响应速度。
它几个关键的配置包括:核心线程数、最大线程数、空闲存活时间、工作队列、拒绝策略。

主要工作原理如下:
- 默认情况下线程不会预创建,任务提交之后才会创建线程(不过设置 prestartAllCoreThreads 可以预创建核心线程)。
- 当核心线程满了之后不会新建线程,而是把任务堆积到工作队列中。
- 如果工作队列放不下了,然后才会新增线程,直至达到最大线程数。
- 如果工作队列满了,然后也已经达到最大线程数了,这时候来任务会执行拒绝策略。
- 如果线程空闲时间超过空闲存活时间,并且当前线程数大于核心线程数的则会销毁线程,直到线程数等于核心线程数(设置 allowCoreThreadTimeOut 为 true 可以回收核心线程,默认为 false)。
Java 的线程池线程数该怎么确定?
线程池的线程数设置需要看具体执行的任务是什么类型的。
任务类型可以分:CPU 密集型任务和 I/O 密集型任务。
CPU 密集型任务
CPU 密集型任务,就好比单纯的数学计算任务,它不会涉及 I/O 操作,也就是说它可以充分利用 CPU 资源(如果涉及 I/O,在进行 I/O 的时候 CPU 是空闲的),不会因为 I/O 操作被阻塞,因此不需要很多线程,线程多了上下文开销反而会变多。
根据经验法则,CPU 密集型任务线程数 = CPU 核心数 + 1
。
I/O 密集型任务
I/O 密集型任务,有很多 I/O 操作,例如文件的读取、数据库的读取等等,任务在读取这些数据的时候,是无法利用 CPU 的,对应的线程会被阻塞等待 I/O 读取完成,因此如果任务比较多,就需要有更多的线程来执行任务,来提高等待 I/O 时候的 CPU 利用率。
根据经验法则,
I/O 密集型任务线程数 = CPU 核心数 * 2
或更多一些。
Thread 的 run 和 start 的区别是什么?
- run 方法描述了线程的任务,如果直接执行 run 方法,那么 Java 会把他当成一个普通的方法,不会新开线程去执行。
- start 方法是让底层操作系统分配线程去执行 run 方法。
Java 提供了哪几个线程池预设模板?
Java 并发库中提供了 5 种常见的线程池实现,主要通过 Executors
工具类来创建。
1)FixedThreadPool:创建一个固定数量的线程池。
线程池中的线程数是固定的,空闲的线程会被复用。如果所有线程都在忙,则新任务会放入队列中等待。
适合负载稳定的场景,任务数量确定且不需要动态调整线程数。
2)CachedThreadPool:一个可以根据需要创建新线程的线程池。
线程池的线程数量没有上限,空闲线程会在 60 秒后被回收,如果有新任务且没有可用线程,会创建新线程。
适合短期大量并发任务的场景,任务执行时间短且线程数需求变化较大。
3)SingleThreadExecutor:创建一个只有单个线程的线程池。
只有一个线程处理任务,任务会按照提交顺序依次执行。
适用于需要保证任务按顺序执行的场景,或者不需要并发处理任务的情况。
4)ScheduledThreadPool:支持定时任务和周期性任务的线程池。
可以定时或以固定频率执行任务,线程池大小可以由用户指定。
适用于需要周期性任务执行的场景,如定时任务调度器。
5)WorkStealingPool:基于任务窃取算法的线程池。
线程池中的每个线程维护一个双端队列(deque),线程可以从自己的队列中取任务执行。如果线程的任务队列为空,它可以从其他线程的队列中“窃取”任务来执行,达到负载均衡的效果。
适合大量小任务并行执行,特别是递归算法或大任务分解成小任务的场景。
线程池中阻塞队列有哪几种?
常见的阻塞队列包括:
- ArrayBlockingQueue:一个有界队列,底层基于数组实现。需要在初始化时指定队列的大小,队列满时,生产者会被阻塞,队列空时,消费者会被阻塞。
- LinkedBlockingQueue:基于链表的阻塞队列,允许可选的界限(有界或无界)。无界模式下可以不断添加元素,直到耗尽系统资源。有界模式则类似于
ArrayBlockingQueue
,但吞吐量通常较高。 - PriorityBlockingQueue:一个无界的优先级队列,元素按照自然顺序或者指定的比较器顺序进行排序。与其他阻塞队列不同的是,PriorityBlockingQueue 不保证元素的 FIFO 顺序。
- DelayQueue:一个无界队列,队列中的元素必须实现
Delayed
接口,只有当元素的延迟时间到期时,才能被取出。常用于延迟任务调度。 - SynchronousQueue:一个没有内部容量的队列,每个插入操作必须等待对应的移除操作,反之亦然。常用于在线程之间的直接传递任务,而不是存储任务。
Java 1.8 版本相比之前有什么新特性?
JDK8 较为重要和平日里经常被问的特性如下:
1)用元空间替代了永久代
因为 JDK8 要把 JRockit 虚拟机和 Hotspot 虚拟机融合,而 JRockit 没有永久代,所以把 Hotspot 永久代给去了(本质也是永久代回收效率太低)。
2)引入了 Lambda 表达式
Lambda 是 Java 8 引入的一种匿名函数,可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。
3)引入了日期类、接口默认方法、静态方法
日期类:
Java 8 引入了新的日期和时间 API(位于 java.time 包中),它们更加简洁和易于使用,解决了旧版日期时间 API 的许多问题。
例如 Date
、Calendar
都是可变类且线程不安全。而新的日期类都是不可变的,一旦创建就不能修改,这样可以避免意外的修改,提升代码的安全性和可维护性。
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();
Date
本身不包含时区信息,必须使用 Calendar
类来处理时区,但使用起来非常复杂且容易出错。
新 API 提供了专门的时区类(如 ZonedDateTime
, OffsetDateTime
, ZoneId
等),简化了时区处理,并且这些类的方法更加直观和易用。
接口默认方法、静态方法:
默认方法允许在接口中定义方法的默认实现,这样接口的实现类不需要再实现这些方法。之所以提供静态方法,是为了将相关的方法内聚在接口中,而不必创建新的对象。
interface MyInterface {
default void defaultMethod() {
System.out.println("Default Method");
}
static void hello() {
System.out.println("Hello, New Static Method Here");
}
}
4)新增 Stream 流式接口
Stream API 提供了一种高效且易于使用的方式来处理数据集合。它支持链式操作、惰性求值和并行处理。
List list = Arrays.asList("a", "b", "c", "d");
List result = list.stream()
.filter(s -> s.startsWith("a"))
.collect(Collectors.toList());
5)引入 Optional 类
Optional
类用来解决可能出现的 NullPointerException
问题,提供了一种优雅的方式来处理可能为空的值。
6)新增了 CompletableFuture 、StampedLock 等并发实现类。
CompletableFuture 提供了一个新的异步编程模型,简化了异步任务的编写和管理。
CompletableFuture.supplyAsync(() -> "Hello")
.thenApply(s -> s + " World")
.thenAccept(System.out::println);
文章篇幅有限,
完整答案可以点击下方小程序进行查阅:、
我们精选了近两年的高频面试真题,已经有 9000 多道面试题目啦,由大厂资深面试官手写答案,押题命中率超高!
不仅有传统八股文,场景题、项目题、系统设计题等等应有尽有,还在不断更新中!
目前优惠最低特价 129 元即永久(限时上架)畅看所有面试题和答案,正式运营价格为 399+,不要错过这次优惠哈!
且,现在邀请好友注册并成为会员,还可获得 10% 的分佣🧧!详情见面试鸭拉新邀请有赏规则(网页版面试鸭点击头像查看)
网页端网址:
www.mianshiya.com
👇 点击下方关注鱼皮,获取免费编程学习路线、简历模板、面试题解、AI 知识库、项目教程、交流群。