IT评测·应用市场-qidao123.com

标题: 1222面经 [打印本页]

作者: 河曲智叟    时间: 2024-12-23 18:55
标题: 1222面经
1,Kafka 如何保障顺序消耗?

Kafka 保障顺序消耗重要通过以下几个关键机制和配置来实现:
分区策略


消耗者配置


  1. import org.apache.kafka.clients.consumer.ConsumerConfig;
  2. import org.apache.kafka.clients.consumer.ConsumerRecords;
  3. import org.apache.kafka.clients.consumer.KafkaConsumer;
  4. import java.util.Arrays;
  5. import java.util.Properties;
  6. public class KafkaConsumerExample {
  7.     public static void main(String[] args) {
  8.         Properties props = new Properties();
  9.         props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
  10.         props.put(ConsumerConfig.GROUP_ID_CONFIG, "test-group");
  11.         props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
  12.         props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
  13.         KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
  14.         consumer.subscribe(Arrays.asList("test-topic"));
  15.         while (true) {
  16.             ConsumerRecords<String, String> records = consumer.poll(100);
  17.             for (var record : records) {
  18.                 System.out.printf("Received message: key = %s, value = %s, partition = %d, offset = %d\n",
  19.                         record.key(), record.value(), record.partition(), record.offset());
  20.             }
  21.         }
  22.     }
  23. }
复制代码

消息确认机制


幂等性和事件支持


2,秒杀场景,如何设计一个秒杀功能?

秒杀场景通常具有高并发、瞬时流量大等特点,设计一个秒杀功能必要从多个方面综合考虑,以下是一个较为全面的设计方案:
前端设计


后端设计


  1. public class SeckillServiceImpl implements SeckillService {
  2.     @Autowired
  3.     private RedisTemplate<String, Object> redisTemplate;
  4.     @Autowired
  5.     private SeckillMapper seckillMapper;
  6.     @Override
  7.     @Transactional
  8.     public boolean seckill(Long seckillId, Long userId) {
  9.         // 从缓存中获取库存
  10.         String stockKey = "seckill:stock:" + seckillId;
  11.         Integer stock = (Integer) redisTemplate.opsForValue().get(stockKey);
  12.         if (stock == null || stock <= 0) {
  13.             return false;
  14.         }
  15.         // 预扣库存,在缓存中减1
  16.         redisTemplate.opsForValue().decrement(stockKey);
  17.         try {
  18.             // 扣减数据库库存
  19.             int result = seckillMapper.reduceStockByOptimisticLock(seckillId);
  20.             if (result > 0) {
  21.                 // 生成订单等后续操作
  22.                 createOrder(seckillId, userId);
  23.                 return true;
  24.             } else {
  25.                 // 库存扣减失败,回滚缓存中的预扣库存
  26.                 redisTemplate.opsForValue().increment(stockKey);
  27.                 return false;
  28.             }
  29.         } catch (Exception e) {
  30.             // 发生异常,回滚缓存中的预扣库存
  31.             redisTemplate.opsForValue().increment(stockKey);
  32.             throw new RuntimeException("秒杀失败", e);
  33.         }
  34.     }
  35. }
复制代码

数据存储设计


高可用设计


3,Redis 长期化机制是什么?

Redis 提供了两种长期化机制,即 RDB(Redis Database)长期化和 AOF(Append Only File)长期化,它们可以将内存中的数据生存到磁盘上,以防止数据丢失,以下是具体介绍:
RDB 长期化


AOF 长期化


混淆长期化


4,解决 Redis 热点 Key 题目标方法有哪些?

Redis 热点 Key 是指在 Redis 中,某些特定的 Key 在一段时间内被大量的请求频繁访问,导致该 Key 地点的 Redis 节点负载过高,大概会影响整个系统的性能和稳固性。以下是一些解决 Redis 热点 Key 题目标方法:
优化 Key 的设计


本地缓存


分布式缓存


限流与降级


数据预热


5,MySQL 主从复制是如何实现的?

MySQL 主从复制是指将一台 MySQL 服务器(主服务器)的数据复制到一台或多台其他 MySQL 服务器(从服务器)的过程,着实现重要涉及以下三个步调:
主服务器配置


从服务器配置


  1. server-id=2
  2. relay-log=mysql-relay-bin
  3. read-only=1
  4. log-slave-updates=1
复制代码
其中,server-id设置为与主服务器差别的值,relay-log指定了中继日记文件的名称,read-only=1表现从服务器默认只提供读操纵,log-slave-updates=1表现从服务器在执行中继日记中的 SQL 语句时也会将其记录到本身的二进制日记中。

复制过程


6,MySQL InnoDB 和 MyISAM 的区别是什么?

MySQL 中的 InnoDB 和 MyISAM 是两种常用的存储引擎,它们在事件支持、锁机制、并发性能等多个方面存在区别,以下是详细介绍:
事件支持


锁机制


并发性能


存储结构


外键支持


缓存机制


数据恢复


7,MySQL 中的 MVCC 是什么?

MVCC 即多版本并发控制(Multi-Version Concurrency Control),是 MySQL 中 InnoDB 存储引擎实现并发控制的一种告急机制,以下是其详细介绍:
根本原理


实现机制


工作过程


优势


8,什么是 Java 中的双亲委派模子?

双亲委派模子是 Java 中类加载器的一种工作机制,以下是关于它的详细介绍:
工作原理


类加载器层次结构


实现代码示例

以下是在 Java 中模拟双亲委派模子的部门代码示例:
  1. public class ClassLoaderTest {
  2.     public static void main(String[] args) {
  3.         // 获取系统类加载器
  4.         ClassLoader applicationClassLoader = ClassLoader.getSystemClassLoader();
  5.         // 获取扩展类加载器
  6.         ClassLoader extensionClassLoader = applicationClassLoader.getParent();
  7.         // 获取引导类加载器
  8.         ClassLoader bootstrapClassLoader = extensionClassLoader.getParent();
  9.         try {
  10.             // 使用系统类加载器加载类
  11.             Class<?> clazz1 = applicationClassLoader.loadClass("java.lang.String");
  12.             System.out.println(clazz1.getClassLoader());
  13.             // 使用扩展类加载器加载类
  14.             Class<?> clazz2 = extensionClassLoader.loadClass("javax.swing.JButton");
  15.             System.out.println(clazz2.getClassLoader());
  16.             // 使用自定义类加载器加载类
  17.             ClassLoader customClassLoader = new CustomClassLoader();
  18.             Class<?> clazz3 = customClassLoader.loadClass("com.example.MyClass");
  19.             System.out.println(clazz3.getClassLoader());
  20.         } catch (ClassNotFoundException e) {
  21.             e.printStackTrace();
  22.         }
  23.     }
  24. }
  25. class CustomClassLoader extends ClassLoader {
  26.     @Override
  27.     public Class<?> loadClass(String name) throws ClassNotFoundException {
  28.         if (!name.startsWith("com.example")) {
  29.             return super.loadClass(name);
  30.         }
  31.         try {
  32.             // 自定义类加载逻辑
  33.             String fileName = name.substring(name.lastIndexOf('.') + 1) + ".class";
  34.             InputStream is = getClass().getResourceAsStream(fileName);
  35.             if (is == null) {
  36.                 return super.loadClass(name);
  37.             }
  38.             byte[] b = new byte[is.available()];
  39.             is.read(b);
  40.             return defineClass(name, b, 0, b.length);
  41.         } catch (IOException e) {
  42.             throw new ClassNotFoundException(name);
  43.         }
  44.     }
  45. }
复制代码
优势


9,synchronized 和 lock 有什么区别?

在 Java 中,synchronized和Lock都可用于实现多线程同步,但在使用方式、功能特性等方面存在一些区别,以下是详细介绍:
用法与语法


功能特性


性能差异


使用场景


10,什么是指令重排序,如何解决?

指令重排序是指在程序执行过程中,编译器和处理器为了优化程序性能,对指令执行的顺序进行重新排列的一种现象。以下是关于指令重排序的详细介绍以及解决方法:
产生缘故原由


大概导致的题目


解决方法


11,Spring loC 和 AOP 是什么?

Spring 是一个开源的 Java 应用程序框架,在企业级 Java 开发中广泛使用。其焦点特性包括控制反转(IoC)和面向切面编程(AOP),以下是对它们的详细介绍:
Spring IoC(Inversion of Control,控制反转)


  1. public class UserService {
  2.     private UserDao userDao;
  3.     public UserService(UserDao userDao) {
  4.         this.userDao = userDao;
  5.     }
  6. }
复制代码

  1. public class UserService {
  2.     private UserDao userDao;
  3.     public void setUserDao(UserDao userDao) {
  4.         this.userDao = userdao;
  5.     }
  6. }
复制代码

  1. public class UserService {
  2.     @Autowired
  3.     private UserDao userDao;
  4. }
复制代码
Spring AOP(Aspect Oriented Programming,面向切面编程)


  1. // 定义切面
  2. @Aspect
  3. public class LoggingAspect {
  4.     // 定义切点
  5.     @Pointcut("execution(* com.example.service.UserService.*(..))")
  6.     public void userServicePointcut() {}
  7.     // 定义前置通知
  8.     @Before("userServicePointcut()")
  9.     public void beforeMethod(JoinPoint joinPoint) {
  10.         System.out.println("Before method: " + joinPoint.getSignature().getName());
  11.     }
  12. }
复制代码
12,解决 Hash 碰撞的方法有哪些?

哈希碰撞(Hash Collision)是指差别的输入经过哈希函数计算后得到了相同的哈希值。解决哈希碰撞的方法有多种,以下是一些常见的方法:
开放定址法


链地点法


再哈希法


建立公共溢出区


13,什么是 ABA 题目?

ABA 题目是在多线程并发编程中,由于对共享资源的访问和修改顺序不同等而导致的一种特殊题目,以下是具体介绍:
题目描述


产生缘故原由


示例

  1. import java.util.concurrent.atomic.AtomicReference;
  2. public class ABAProblemExample {
  3.     private static AtomicReference<String> atomicReference = new AtomicReference<>("A");
  4.     public static void main(String[] args) throws InterruptedException {
  5.         Thread thread1 = new Thread(() -> {
  6.             String prev = atomicReference.get();
  7.             System.out.println("Thread 1 read value: " + prev);
  8.             // 模拟一些耗时操作
  9.             try {
  10.                 Thread.sleep(1000);
  11.             } catch (InterruptedException e) {
  12.                 e.printStackTrace();
  13.             }
  14.             boolean result = atomicReference.compareAndSet("A", "B");
  15.             System.out.println("Thread 1 CAS result: " + result);
  16.             result = atomicReference.compareAndSet("B", "A");
  17.             System.out.println("Thread 1 CAS result: " + result);
  18.         });
  19.         Thread thread2 = new Thread(() -> {
  20.             try {
  21.                 Thread.sleep(2000);
  22.             } catch (InterruptedException e) {
  23.                 e.printStackTrace();
  24.             }
  25.             boolean result = atomicReference.compareAndSet("A", "C");
  26.             System.out.println("Thread 2 CAS result: " + result);
  27.         });
  28.         thread1.start();
  29.         thread2.start();
  30.         thread1.join();
  31.         thread2.join();
  32.     }
  33. }
复制代码
在上述示例中,thread1首先读取atomicReference的值为"A",然后经过一些操纵将其值从"A"修改为"B",再修改回"A"。而thread2在thread1操纵完成后,也尝试将atomicReference的值从"A"修改为"C",此时thread2的compareAndSet操纵会成功,由于它看到的值也是"A",但实际上这个"A"已经不是最初的谁人"A"了,这就大概导致程序出现意外的结果。
解决方法


14,算法:反转链表

以下是使用 Java 语言实现反转链表的几种常见算法,这里以单链表为例进行介绍:
迭代法


  1. class ListNode {
  2.     int val;
  3.     ListNode next;
  4.     ListNode(int val) {
  5.         this.val = val;
  6.     }
  7. }
  8. public class ReverseLinkedList {
  9.     public ListNode reverseList(ListNode head) {
  10.         ListNode prev = null;
  11.         ListNode curr = head;
  12.         while (curr!= null) {
  13.             ListNode nextTemp = curr.next;
  14.             curr.next = prev;
  15.             prev = curr;
  16.             curr = nextTemp;
  17.         }
  18.         return prev;
  19.     }
  20. }
复制代码
递归法


  1. class ListNode {
  2.     int val;
  3.     ListNode next;
  4.     ListNode(int val) {
  5.         this.val = val;
  6.     }
  7. }
  8. public class ReverseLinkedList {
  9.     public ListNode reverseList(ListNode head) {
  10.         if (head == null || head.next == null) {
  11.             return head;
  12.         }
  13.         ListNode reversedSubList = reverseList(head.next);
  14.         head.next.next = head;
  15.         head.next = null;
  16.         return reversedSubList;
  17.     }
  18. }
复制代码
在实际应用中,可以根据具体的场景选择符合的方法来反转链表,迭代法相对来说更容易理解和实现,递归法则代码更加简便,但在处理较长链表时大概会有栈溢出的风险(取决于递归深度)。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4