首页 > 编程语言 >Java开发常见问题分析

Java开发常见问题分析

时间:2023-11-21 13:55:46浏览次数:36  
标签:常见问题 Java Redis 开发 线程 消息 使用 多线程 数据

程序Bug的产生,通常分为三种类型

  1. 逻辑漏洞
    低级错误,程序执行后无法达到想要效果。

  2. 越界访问
    访问了非法区域,造成程序崩溃。

  3. 条件考虑不全面
    你以为你万无一失,但你永远都不知道输入参数究竟是什么!

如何防范未知Bug:异常捕获

异常捕获一般依靠try,catch语句。很好理解:try(尝试)一下,如果有问题,直接捕获 (catch)住,防止程序崩溃。

如果核心流程处理到一半服务器崩了怎么处理?

这里同时存在三个问题:

  • 问题排查以及快速恢复
  • 异常数据修复
  • 服务高可用,规避服务宕机

1、先抢通业务

当发现服务器宕机后,最关键的是抢通业务,而不是抢修服务器。

因此,需要做应急方案。最好准备2个网站服务器,他们存放的内容相同,而ip不同,并且机房的地理位置不同。这样第一时间发现宕机问题后,可以迅速的通过修域名记录,指向目前正常的网站空间。而且2个主机,同时宕机的可能性就大大降低了。

2、定位服务器崩溃原因

  • 内存溢出,磁盘资源耗尽
  • 线程死锁,进程过多或者不断创建,耗尽资源导致
  • 数据库慢查询,连接数过多,临时表不够用,程序死锁
  • 主备数据不一致
  • 应用程序异常
  • 流量负载过大
  • DOSS攻击
  • 散热问题

3、异常数据修复

  • 写数据做事务控制,保障数据安全。
  • 磁盘备份,重启服务时恢复数据。
  • 记录关键日志。

4、服务高可用

  • 服务多实例集群部署,负载均衡策略访问,做好服务降级、服务限流。
  • 数据库读写分离、分库分表方案。
  • 做好服务性能测试、压力测试。

开发中常见问题

空指针异常

在访问或操作对象之前,检查对象是否为null

类型转换异常

在进行类型转换之前,先检查对象的类型是否与目标类型兼容。

金额数值计算精度问题

金额一般都是用BigDecimal

循环条件错误

可能会导致死循环或者无法执行

文件操作异常

文件操作之前,先检查文件是否存在、是否可读写等。

事务不起作用没有回滚

异常被try.catch吃了,手动抛了别的异常Exception,默认情况下只会回滚RuntimeException
访问权限不是public;方法用final,static修饰;方法内部调用;
未开启事务;未被spring管理,需要创建bean实例。

内存溢出异常

在编写程序时,要注意控制内存的使用,及时释放不需要的对象。

性能问题

比如使用缓存、减少对象创建、优化算法等。

大数据量导出Excel存在问题及优化方案

问题1:一次性获取全部数据到内存当中,容易引起系统OOM。
解决方案:分页查询数据,分批处理。

问题2:分页查询存在深度分页问题,数据偏移量越大导致sqL查询变慢。
解决方案:使用标签记录优化(id自增且连续)、索引覆盖优化。

问题3:查询数据串行耗时长。
解决方案:可以通过线程编排,并行执行sql查询,最后顺序导出到excel。

问题4:一个excel文件数据过大,用户存在打不开的情况。
解决方案:通过easyexcel多sheet页导出数据。

实际开发中,如何正确使用多线程?

  1. 处理并行任务:多线程可以同时处理多个任务,提高程序的执行效率。比如批量处理数据、同时上传多个文件等。
  2. 事件驱动的编程:Java多线程可以用于事件驱动的编程,如GUI、网络编程等。
  3. 并发访问共享资源:多线程可以应用于并发访问共享资源的场景,如数据库连接池。
  4. 高效的IO操作:在网络编程中,Java多线程可以提供高效的IO操作,如同时读写多个Socket。
  5. 多任务协同处理:在复杂的任务中,不同的任务可以以各自独立的方式并行运行,最终合并结果。
  6. 节约资源:多线程可以提高CPU和内存的使用效率,使得我们能够更好地利用系统资源。
  7. 提高用户体验:在一些高并发场景下,如网站、游戏等,使用多线程可以提高用户体验,使得用户能够更快地得到反馈。

常见的多线程问题包括

  1. 线程安全问题
    多个线程同时访问共享资源时可能导致数据不一致或异常。解决方案包括使用同步机制(如synchronized关键字、Lock对象)、使用线程安全的数据结构、避免共享状态等。
  2. 死锁问题
    多个线程因相互等待对方释放资源而无法继续执行。解决方案包括避免循环等待资源、按照固定顺序获取资源、设置超时时间等。
  3. 上下文切换问题
    线程切换需要耗费一定的时间和资源,如果线程频繁切换,会降低程序性能。解决方案包括合理设计线程数量、减少线程间的竞争、使用线程池等。
  4. 数据同步问题
    多个线程访问共享数据时,可能出现数据不一致的问题。解决方案包括使用锁来保证数据的原子性、使用volatile关键字保证可见性、使用线程安全的数据结构等。
  5. 过度创建线程问题
    创建线程需要消耗系统资源,如果过度创建线程,可能导致系统资源耗尽。解决方案包括使用线程池来复用线程、合理设置线程池大小等。

定时任务如果集群,如何保证不被重复执行?

  1. 独立部署,将定时任务独立出来,成为一个单独的项目工程,单一部署
  2. 配置实现,配置文件设置一个标识符号,定时任务读取此配置文件此属性, 读取到ture执行定时任务,否则不执行
  3. 利用分布式锁,虽然两个机器都会运行定时任务,但是一个时刻只有一台机器会真正的执行定时任务的核心方法

一个订单30分钟未支付自动取消功能,有几种实现方案?

  1. 数据库轮询
    该方案通常是在小型项目中使用,即通过一个线程定时的去扫描数据库,通过订单时间来判断是否有超时的订单,然后进行 update 或 delete 等操作。

    优点:简单易行,支持集群操作。
    缺点:对服务器内存消耗大;
    存在延迟,比如你每隔 3 分钟扫描一次,那最坏的延迟时间就是 3 分钟;
    假设你的订单有几千万条,每隔几分钟这样扫描一次,数据库损耗极大。

  2. JDK 的延迟队列
    该方案是利用 JDK 自带的 DelayQueue 来实现,这是一个无界阻塞队列,该队列只有在延迟期满的时候才能从中获取元素,放入 DelayQueue 中的对象,是必须实现 Delayed 接口的。

    优点:效率高,任务触发时间延迟低。
    缺点:服务器重启后,数据全部消失,怕宕机;集群扩展相当麻烦;代码复杂度较高;
    因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现 OOM 异常。

  3. 时间轮算法
    时间轮算法可以类比于时钟,按某一个方向按固定频率轮动,每一次跳动称为一个 tick。

    优点:效率高,任务触发时间延迟时间比 delayQueue 低,代码复杂度比 delayQueue 低。
    缺点:服务器重启后,数据全部消失,怕宕机;集群扩展相当麻烦;
    因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现 OOM 异常。

  4. Redis 缓存
    思路一:利用 Redis 的 zset,zset 是一个有序集合,每一个元素 (member) 都关联了一个 score, 通过 score 排序来取集合中的值。
    思路二:使用 Redis 的 Keyspace Notifications,中文翻译就是键空间机制,就是利用该机制可以在 key 失效之后,提供一个回调,实际上是 Redis 会给客户端发送一个消息。是需要 Redis 版本 2.8 以上。

    优点:由于使用 Redis 作为消息通道,消息都存储在 Redis 中。如果发送程序或者任务处理程序挂了,重启之后,还有重新处理数据的可能性;做集群扩展相当方便;时间准确度高。
    缺点:需要额外进行 Redis 维护。

  5. 使用消息队列
    可以采用 RabbitMQ 的延时队列。RabbitMQ可以实现延迟队列。

    优点:高效,可以利用 RabbitMQ 的分布式特性轻易的进行横向扩展,消息支持持久化增加了可靠性。
    缺点:本身的易用度要依赖于 RabbitMQ 的运维。因为要引用 RabbitMQ, 所以复杂度和成本变高。

为什么不用eureka非要用nacos作为注册中心?

nacos在自动或手动下线服务,使用消息机制通知客户端,服务实例的修改很快响应;Eureka只能通过任务定时剔除无效的服务。
nacos可以根据namespace命名空间,DataId,Group分组,来区分不同环境(dev,test,prod),不同项目的配置。

Mq如何保证消息不丢失?

丢数据一般分为两种,一种是mq把消息丢了,一种就是消费时将消息丢了。

Mq如何保证消息顺序的一致性?

如何避免消息一直堆积在mq服务器端?

在遇到消息堆积的时候,先检查下导致堆积的原因,可能有如下几种:

  1. 消费失败时大量重试导致消息堆积。
  2. 消费者程序的故障:如 程序死锁,io阻塞等。
  3. 消费者资源瓶颈:目前的主流消息队列,单个节点消息收发的性能可以达到万级别甚至10万级+的水平。除非容量预估没有做好,一般不会出现这种问题。即使出现这种问题,通过Scale Out Broker 的实例数也是比较轻松可以解决的。

消息堆积的解决方案:

  1. 提高消费者数量;更多的消费者将允许同时处理更多的消息,并减少消息堆积。
  2. 调整超时设置;例如,在某些情况下,因为某些原因(例如网络延迟),MQ 消费者需要等待更长时间才能接收到新的消息。
  3. 批量操作;例如,在生产者端,您可以使用管道来一次性发送多条信息。在消费者端,您可以使用批处理来一次性处理多个消息。
  4. 数据结构优化;例如,在使用MQ时,可以通过在消息中添加一些元信息来优化处理流程,或者采用更合适的数据结构存储消息,以减少在 MQ 中积累的消息数量。

Mq异步消费,如何获取到返回结果?

以下用Rabbit为例:

  1. 异步操作,获取回调消费结果,需要实现RabbitTemplate.ConfirmCallback 接口,然后重写 confirm()方法。
  2. 获取回调结果,指的是获取消息是否被消费端正常消费而返回的结果,并不是消费端返回的处理结果,这一点得注意,如果需要等待消费端返回处理结果,则需要做同步操作,而不是做回调操作。
  3. 需要做同步操作时,应该rabbitTemplate.convertSendAndReceive()方法,返回结果类型是Object,需要根据消费端返回的数据类型来决定强转的类型。
  4. 异步则使用rabbitTemplate.convertAndSend()方法。

标签:常见问题,Java,Redis,开发,线程,消息,使用,多线程,数据
From: https://www.cnblogs.com/zhaojinhui/p/17846423.html

相关文章

  • 2023-11-21 托管第三方开发的小程序如何加急发布?==》需要调用微信提供的接口去发布
    接口地址:https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/code-management/speedupCodeAudit.html 你可以在这里调试:https://developers.weixin.qq.com/apiExplorer?apiName=startPushTicket&plat=thirdparty 注:审核单id为你提......
  • Java -day4
    4.7稀疏数组publicstaticvoidmain(String[]args){int[][]array1=newint[11][11];array1[1][2]=1;array1[2][3]=2;System.out.println("原始数组");for(int[]ints:array1){for(intanInt......
  • 使用Java与MySQL开发计算器
    [实验目的]1.掌握软件开发的基本流程2.掌握常用的软件开发方式和工具。[实验内容]设计一个包含登录界面的计算器软件,该软件可以实现第一次作业中的全部功能,同时可以保存用户的历史计算记录(保存数据最好使用数据库)。[实验环境及开发工具]使用MicrosoftVisio作绘图工具使用......
  • 《最新出炉》系列初窥篇-Python+Playwright自动化测试-31-JavaScript的调用执行-上篇
    1.简介在做web自动化时,有些情况playwright的api无法完成以及无法应对,需要通过或者借助第三方手段比如js来完成实现,比如:去改变某些元素对象的属性或者进行一些特殊的操作,本文讲解playwright怎样来调用JavaScript完成特殊操作。2.用法上一篇中就提到过,这里提取一下,语法如下:......
  • Java中的位运算符介绍
    一、Java中的位运算符Java提供了6种基本的位运算符,它们用于直接操作二进制数位,分别是:位与运算符(&)作用:对两个数的每一位执行与操作,只有在对应位都为1时结果才为1。示例:1intresult=5&3;//Result:1(0b0101&0b0011)位或运算符(|)作用:对两个数的每一......
  • 用java框架spring boot写一个文件上传
    在SpringBoot中,实现文件上传可以使用SpringFramework提供的MultipartResolver。以下是一个简单的SpringBoot文件上传示例:在POM文件中添加以下依赖:<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></depend......
  • JAVA之List过滤
    List过滤的三种方式:通过java8中filter过滤器进行过滤通过For循环遍历过滤通过ForEach遍历过滤publicclassFilteringList{/***通过java8中filter过滤器进行过滤*@paramuserList*@return*/publicList<User>filterByStream(List......
  • Spring_2023_11_21_1 使用javaConfig实现DI
    Spring_Aop2023_11_21_1使用javaConfig实现DIjavaConfig,是在Spring3.0开始从一个独立的项目并入到Spring中的。javaConfig可以看成一个用于完成Bean装配的Spring配置文件,即Spring容器,只不过该容器不是XML文件,而是由程序员使用java自己编写的java类。一个类中......
  • 开发中遇到的问题总结---java中list和Collection之间的转换
    问题描述:将map中的values转换为list错误做法:强制转换(会报错)List<String>originalContractCodeList=(List<String)kpmcKpidMap.values();正确做法:List<String>originalContractCodeList=newArrayList<>(kpmcKpidMap.values());......
  • JavaScript-触摸操作
    触摸操作概述浏览器的触摸API由三个部分组成。Touch:一个触摸点TouchList:多个触摸点的集合TouchEvent:触摸引发的事件实例Touch接口的实例对象用来表示触摸点(一根手指或者一根触摸笔),包括位置、大小、形状、压力、目标元素等属性。有时,触摸动作由多个触摸点(多根手指)组成,多个触摸点的......