前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >阿里年包80万,还是洒水车司机月薪3000

阿里年包80万,还是洒水车司机月薪3000

作者头像
沉默王二
发布2024-06-04 20:37:42
970
发布2024-06-04 20:37:42
举报
文章被收录于专栏:沉默王二沉默王二

牛客上刷到一条帮选 offer 的帖子,上来就是“阿里 80 万年包,边缘业务”,于是很有诚意的点进去,想帮牛友分担一点选择上的负担,结果看得汗流浃背。

截图来自牛客

直到“洒水车司机,月薪 3000”的出现,又突然释怀的笑了(😂)~

你别说,我小学有个同学真在郑州开洒水车(真事),薪资比 3000 高一些,上次我表弟结婚的时候他也回村了,我们聊的还挺开心。我俩同届,从育红班开始一起上学到初中一年级他辍学,7 年时间。

话说回来,阿里 80 万年包,和洒水车司机月薪 3000元,我估计 99.9% 的同学都会毫不犹豫的选择阿里。

互联网高速发展到现在,很卷,阿里也是各种大厂病,最近几年一直在治。从下面这幅图大家应该能感受出来阿里的变化,从巅峰时期的 25 万员工减少到现在的 20 多万员工。

截图来自市界

但即便如此,如果有阿里的 offer 摆在同学们的面前,我相信大家依然会毫不犹豫地冲,毕竟下山的神仍然是神。我也希望国内的所有互联网公司都能走出低谷,重现辉煌,也只有这样,大家的就业选择才会多起来。

这次我们就以《Java 面试指南-阿里面经》同学 1 的后端面试为例,来看看阿里面试官都喜欢问哪些八股,好背的滚瓜烂熟,了然于胸,25 届的同学加把劲。

让天下所有的面渣都能逆袭 😁

题目不多,主要还是围绕着二哥强调的 Java 后端四大件为主,所以大家在准备的时候一定要有的放矢,知道哪些是重点。

阿里面经(闲鱼一面)

spring的bean的并发安全问题

Spring Bean 的默认作用域是单例(Singleton),这意味着 Spring 容器中只会存在一个 Bean 实例,并且该实例会被多个线程共享。

如果单例 Bean 是无状态的,也就是没有成员变量,那么这个单例 Bean 是线程安全的。比如 Spring MVC 中的 Controller、Service、Dao 等,基本上都是无状态的。

但如果 Bean 的内部状态是可变的,且没有进行适当的同步处理,就可能出现线程安全问题。

三分恶面渣逆袭:Spring单例Bean线程安全问题

单例 Bean 线程安全问题怎么解决呢?

第一,使用局部变量。局部变量是线程安全的,因为每个线程都有自己的局部变量副本。尽量使用局部变量而不是共享的成员变量。

代码语言:javascript
复制
public class MyService {
    public void process() {
        int localVar = 0;
        // 使用局部变量进行操作
    }
}

第二,尽量使用无状态的 Bean,即不在 Bean 中保存任何可变的状态信息。

代码语言:javascript
复制
public class MyStatelessService {
    public void process() {
        // 无状态处理
    }
}

第三,同步访问。如果 Bean 中确实需要保存可变状态,可以通过 synchronized 关键字或者 Lock 接口来保证线程安全。

代码语言:javascript
复制
public class MyService {
    private int sharedVar;

    public synchronized void increment() {
        sharedVar++;
    }
}

或者将 Bean 中的成员变量保存到 ThreadLocal 中,ThreadLocal 可以保证多线程环境下变量的隔离。

代码语言:javascript
复制
public class MyService {
    private ThreadLocal<Integer> localVar = ThreadLocal.withInitial(() -> 0);

    public void process() {
        localVar.set(localVar.get() + 1);
    }
}

再或者使用线程安全的工具类,比如说 AtomicInteger、ConcurrentHashMap、CopyOnWriteArrayList 等。

代码语言:javascript
复制
public class MyService {
    private ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

    public void putValue(String key, String value) {
        map.put(key, value);
    }
}

第四,将 Bean 定义为原型作用域(Prototype)。原型作用域的 Bean 每次请求都会创建一个新的实例,因此不存在线程安全问题。

代码语言:javascript
复制
@Component
@Scope("prototype")
public class MyService {
    // 实例变量
}

B+树和B树的对比

B+ 树相比较 B 树,有这些优势:

①、更高的查询效率

B+树的所有值(数据记录或指向数据记录的指针)都存在于叶子节点,并且叶子节点之间通过指针连接,形成一个有序链表。

极客时间:B+树

这种结构使得 B+树非常适合进行范围查询——一旦到达了范围的开始位置,接下来的元素可以通过遍历叶子节点的链表顺序访问,而不需要回到树的上层。如 SQL 中的 ORDER BY 和 BETWEEN 查询。

极客时间:B 树

而 B 树的数据分布在整个树中,进行范围查询时可能需要遍历树的多个层级。

②、更高的空间利用率

在 B+树中,非叶子节点不存储数据,只存储键值,这意味着非叶子节点可以拥有更多的键,从而有更多的分叉。

这导致树的高度更低,进一步降低了查询时磁盘 I/O 的次数,因为每一次从一个节点到另一个节点的跳转都可能涉及到磁盘 I/O 操作。

③、查询效率更稳定

B+树中所有叶子节点深度相同,所有数据查询路径长度相等,保证了每次搜索的性能稳定性。而在 B 树中,数据可以存储在内部节点,不同的查询可能需要不同深度的搜索。

上线的业务出了问题怎么调试,比如某个线程cpu占用率高,怎么看堆栈信息

三分恶面渣逆袭:CPU飙高

首先,使用 top 命令查看 CPU 占用情况,找到占用 CPU 较高的进程 ID。

代码语言:javascript
复制
top

haikuotiankongdong:top 命令结果

接着,使用 jstack 命令查看对应进程的线程堆栈信息。

代码语言:javascript
复制
jstack -l <pid> > thread-dump.txt

上面👆🏻这个命令会将所有线程的堆栈信息输出到 thread-dump.txt 文件中。

然后再使用 top 命令查看进程中线程的占用情况,找到占用 CPU 较高的线程 ID。

代码语言:javascript
复制
top -H -p <pid>

haikuotiankongdong:Java 进程中的线程情况

注意,top 命令显示的线程 ID 是十进制的,而 jstack 输出的是十六进制的,所以需要将线程 ID 转换为十六进制。

代码语言:javascript
复制
printf "%x\n" PID

在 jstack 的输出中搜索这个十六进制的线程 ID,找到对应的堆栈信息。

代码语言:javascript
复制
"Thread-5" #21 prio=5 os_prio=0 tid=0x00007f812c018800 nid=0x1a85 runnable [0x00007f811c000000]
   java.lang.Thread.State: RUNNABLE
    at com.example.MyClass.myMethod(MyClass.java:123)
    at ...

最后,根据堆栈信息定位到具体的业务方法,查看是否有死循环、频繁的垃圾回收(GC)、资源竞争(如锁竞争)导致的上下文频繁切换等问题。

乐观锁、悲观锁、ABA问题

对于悲观锁来说,它总是认为每次访问共享资源时会发生冲突,所以必须对每次数据操作加上锁,以保证临界区的程序同一时间只能有一个线程在执行。

悲观锁的代表有 synchronized 关键字和 Lock 接口。

乐观锁,顾名思义,它是乐观派。乐观锁总是假设对共享资源的访问没有冲突,线程可以不停地执行,无需加锁也无需等待。一旦多个线程发生冲突,乐观锁通常使用一种称为 CAS 的技术来保证线程执行的安全性。

由于乐观锁假想操作中没有锁的存在,因此不太可能出现死锁的情况,换句话说,乐观锁天生免疫死锁。

  • 乐观锁多用于“读多写少“的环境,避免频繁加锁影响性能;
  • 悲观锁多用于”写多读少“的环境,避免频繁失败和重试影响性能。

CAS 存在三个经典问题,ABA 是其中一个。

三分恶面渣逆袭:CAS三大问题

什么是 ABA 问题?如何解决?

如果一个位置的值原来是 A,后来被改为 B,再后来又被改回 A,那么进行 CAS 操作的线程将无法知晓该位置的值在此期间已经被修改过。

可以使用版本号/时间戳的方式来解决 ABA 问题。

比如说,每次变量更新时,不仅更新变量的值,还更新一个版本号。CAS 操作时不仅要求值匹配,还要求版本号匹配。

Java 的 AtomicStampedReference 类就实现了这种机制,它会同时检查引用值和 stamp 是否都相等。

二哥的 Java 进阶之路:AtomicStampedReference

Mysql慢查询问题

顾名思义,慢 SQL 也就是执行时间较长的 SQL 语句,MySQL 中 long_query_time 默认值是 10 秒,也就是执行时间超过 10 秒的 SQL 语句会被记录到慢查询日志中。

定位慢 SQL 主要通过两种手段:

  • 慢查询日志:开启 MySQL 慢查询日志,再通过一些工具比如 mysqldumpslow 去分析对应的慢查询日志,找出问题的根源。
  • 服务监控:可以在业务的基建中加入对慢 SQL 的监控,常见的方案有字节码插桩、连接池扩展、ORM 框架过程,对服务运行中的慢 SQL 进行监控和告警。

也可以使用 show processlist; 查看当前正在执行的 SQL 语句,找出执行时间较长的 SQL。

找到对应的慢 SQL 后,使用 EXPLAIN 命令查看 MySQL 是如何执行 SQL 语句的,这会帮助我们找到问题的根源。

代码语言:javascript
复制
EXPLAIN SELECT * FROM your_table WHERE conditions;

订单超时,用springtask资源占用太高,有什么其他的方式解决?

第一,使用消息队列,如 RabbitMQ、Kafka、RocketMQ 等,将任务放到消息队列中,然后由消费者异步处理这些任务。

①、在订单创建时,将订单超时检查任务放入消息队列,并设置延迟时间(即订单超时时间)。

代码语言:javascript
复制
@Service
public class OrderService {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void createOrder(Order order) {
        // 创建订单逻辑
        // ...
        
        // 发送延迟消息
        rabbitTemplate.convertAndSend("orderExchange", "orderTimeoutQueue", order, message -> {
            message.getMessageProperties().setExpiration("600000"); // 设置延迟时间(10分钟)
            return message;
        });
    }
}

②、使用消费者从队列中消费消息,当消费到超时任务时,执行订单超时处理逻辑。

代码语言:javascript
复制
@Service
public class OrderTimeoutConsumer {

    @RabbitListener(queues = "orderTimeoutQueue")
    public void handleOrderTimeout(Order order) {
        // 处理订单超时逻辑
        // ...
    }
}

第二,使用数据库调度器(如 Quartz)

①、创建一个 Quartz 任务类,处理订单超时逻辑。

代码语言:javascript
复制
public class OrderTimeoutJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 获取订单信息
        Order order = (Order) context.getJobDetail().getJobDataMap().get("order");

        // 处理订单超时逻辑
        // ...
    }
}

②、在订单创建时,调度一个 Quartz 任务,设置任务的触发时间为订单超时时间。

代码语言:javascript
复制
@Service
public class OrderService {
    @Autowired
    private Scheduler scheduler;

    public void createOrder(Order order) {
        // 创建订单逻辑
        // ...

        // 调度 Quartz 任务
        JobDetail jobDetail = JobBuilder.newJob(OrderTimeoutJob.class)
                .usingJobData("order", order)
                .build();

        Trigger trigger = TriggerBuilder.newTrigger()
                .startAt(new Date(System.currentTimeMillis() + 600000)) // 设置触发时间(10分钟后)
                .build();

        try {
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

ThreadLocal存什么东西

ThreadLocal 是 Java 中提供的一种用于实现线程局部变量的工具类。它允许每个线程都拥有自己的独立副本,从而实现线程隔离,用于解决多线程中共享对象的线程安全问题。

三分恶面渣逆袭:ThreadLocal线程副本

在 Web 应用中,可以使用 ThreadLocal 存储用户会话信息,这样每个线程在处理用户请求时都能方便地访问当前用户的会话信息。

在数据库操作中,可以使用 ThreadLocal 存储数据库连接对象,每个线程有自己独立的数据库连接,从而避免了多线程竞争同一数据库连接的问题。

在格式化操作中,例如日期格式化,可以使用 ThreadLocal 存储 SimpleDateFormat 实例,避免多线程共享同一实例导致的线程安全问题。

线程之间传递信息?

线程之间传递信息有多种方式,每种方式适用于不同的场景。比如说使用共享对象、wait()notify()、Exchanger 和 CompletableFuture。

我简单说一下 CompletableFuture 吧,它是 Java 8 引入的一个类,支持异步编程,允许线程在完成计算后将结果传递给其他线程。

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 模拟长时间计算
            return "Message from CompletableFuture";
        });

        future.thenAccept(message -> {
            System.out.println("Received: " + message);
        });
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 沉默王二 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 阿里面经(闲鱼一面)
    • spring的bean的并发安全问题
      • 单例 Bean 线程安全问题怎么解决呢?
    • B+树和B树的对比
      • 上线的业务出了问题怎么调试,比如某个线程cpu占用率高,怎么看堆栈信息
        • 乐观锁、悲观锁、ABA问题
          • 什么是 ABA 问题?如何解决?
        • Mysql慢查询问题
          • 订单超时,用springtask资源占用太高,有什么其他的方式解决?
            • ThreadLocal存什么东西
              • 线程之间传递信息?
              相关产品与服务
              数据库
              云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档