Java常见场景题

1、如果一个外卖配送单子要发布,现在有200个骑手都想要接这一单,如何保证只有一个骑手接到单子?

如果只是单机,采用volatile关键字修饰该订单采用CAS操作对其进行乐观锁操作。
采用redis,zookeeper分布式锁加锁。
消息队列 实现幂等接口

2、多个微信用户抢红包

这个和上题一样的道理

3、美团首页每天会从 10000 个商家里面推荐 50 个商家置顶,每个商家有一个权值,你如何来推荐?第二天怎么更新推荐的商家?

可以借鉴下 stackoverflow,视频网站等等的推荐算法。

4、1000个任务分给10个人做

  • hash
  • 创建10个线程,然后用同步锁,Synchornized

5、保证发送消息的有序性,消息处理的有序性。

6、如何把一个文件快速下发到 100w 个服务器

采用p2p网络形式 比如树状形式,网状形式 单个节点既可以从其他节点接收服务又可以向其他节点提供服务。

对于树状传递,在100W台服务器这种量级上,可能存在两个问题

  1. 如果树上的某一个节点坏掉了,那么从这个节点往下的所有服务器全部宕机。
  2. 如果树中的某条路径,传递时间太长了(网络中,两个节点间的传递速度受很多因素的影响,可能相差成百上千倍),使得传递效率退化。

改进:100W台服务器相当于有100W个节点的连通图。那么我们可以在图里生成多颗不同的生成树,在进行数据下发时,同时按照多颗不同的树去传递数据。这样就可以避免某个中间节点宕机,影响到后续的节点。同时这种传递方法实际上是一种依据时间的广度优先遍历,可以避免某条路径过长造成的效率低下。

7、给每个组分配不同的 IP 段,怎么设计一种结构使的快速得知 IP 是哪个组的?

难道不是划分子网,添加子网掩码

8、10 亿个数,找出最大的 10 个。

(1)单机+单核+足够大内存

  维护一个小顶堆 每一次都与顶堆即最小的数进行比较。如果某一后续元素比容器内最小数字大,则删掉容器内最小元素,并将该元素插入容器

(2)单机+多核+足够大内存

   这时可以直接在内存总使用Hash方法将数据划分成n个partition,每个partition交给一个线程处理,线程的处理逻辑同(1)类似,最后一个线程将结果归并。

  该方法存在一个瓶颈会明显影响效率,即数据倾斜。每个线程的处理速度可能不同,快的线程需要等待慢的线程,最终的处理速度取决于慢的线程。而针对此问题,解决的方法是,将数据划分成c×n个partition(c>1),每个线程处理完当前partition后主动取下一个partition继续处理,知道所有数据处理完毕,最后由一个线程进行归并。

9、有几台机器存储着几亿淘宝搜索日志,你只有一台 2g 的电脑,怎么选出搜索热度最高的十个

可以拆分成n多个文件:以首字母区分,不同首字母放在不同文件,长度仍过长的继续按照次首字母进行拆分

这样一来,每个文件的每个数据长度相同且首字母尾字母也相同,就能保证数据被独立的分为了n个文件,且各个文件中不存在关键词的交集。

对于每个文件,使用hash或者Trie树进行进行词频统计并用大根堆获取词频最多的10个词。依次处理每个文件,并逐渐更新最大的十个词

10、分布式集群中如何保证线程安全?

11、给个淘宝场景,怎么设计一消息队列?

https://blog.csdn.net/gv7lzb0y87u7c/article/details/91443605https://www.jianshu.com/p/3ebde7d36460

12、10 万个数,输出从小到大?

  • 多路归并排序算法 在N个数中取M个数排序后放到内存中,然后多路归并算法进行合并
  • 采用位图标志该数量的个数 标志完成后再遍历bitmap进行排序

13、有十万个单词,找出重复次数最高十个?

针对top k类问题,通常比较好的方案是【分治+trie树/hash+小顶堆】,即先将数据集按照hash方法分解成多个小数据集,然后使用trie树或者hash统计每个小数据集中的query词频,之后用小顶堆求出每个数据集中出频率最高的前K个数,最后在所有top K中求出最终的top K。类似上面第8题

14、在2.5亿个整数中找出不重复的整数,内存不足以容纳这2.5亿个整数

位操作。采用bitmap方法来对每一个数据进行标记。0代表存在,1代表不存在。

15、两个线程交替打印

第一种方法:加锁,并使用volatile boolean类型的标志来控制线程执行

public class sub2{
    static volatile int num=1;
    static volatile boolean flag=true;
    public static void main(String[] args) {
        Object obj=new Object();
        new Thread(()->{
            while(num<=100){
                if(flag){
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num++;
                    flag=false;
                }
            }
        },"A").start();
        new Thread(()->{
            while(num<=100){
                if(!flag){
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num++;
                    flag=true;
                }
            }
        },"B").start();
    }
}

第二种方法:加锁,一个线程执行完就等待并唤醒另一个线程

public class sub2{
    static volatile int num=1;
    public static void main(String[] args) {
        Object obj=new Object();
        new Thread(()->{
            while(num<=100){
                synchronized (obj){
                    obj.notifyAll();
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num++;
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"A").start();
        new Thread(()->{
            while(num<=100) {
                synchronized (obj){
                    obj.notifyAll();
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num++;
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"B").start();
    }

}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐