点击上方“Java编程精选”,选择“热门公众号”

关键时刻,尽快交付!

JSON对象解析过程中,尽量避免多次解析; 如果没有必要,尽量减少对 JSON 对象的重复解析。

在使用Redis或者数据库查询时,如果是有逻辑上下文的代码,尽量避免重复使用同一个查询。 原则是:能少检查一次就少检查一次。 查询结果建议必须做出一定的非空或其他异常判断等。

在进行业务逻辑计算和IO读写操作时,建议分别使用不同的线程。 例如:业务逻辑计算可以使用CPU密集型线程池; 而IO操作可以使用IO类型的线程。 是一个不错的选择工具,值得尝试!

使用重试逻辑时不要太暴力。

如下图所示,Redis可能会超时,而这里的业务比较重要,所以需要添加重试逻辑,而添加的重试逻辑太暴力了。

java代码_代码java下载文件_代码jakarta

这样可能得不到理想的效果,反而会增加Redis的负担,所以建议添加适当的暂停时间。 如下所示:

java代码_代码java下载文件_代码jakarta

在查询数据库或Redis等时,应尽可能给出返回值,并且当前后代码存在顺序依赖关系时,应给出必要的逻辑判断。 尽量不要像下面这样,无论进入数据库后如何。 因为操作可能会失败,一旦这里失败,其他有依赖的地方就会出现问题,代码应该尽量考虑失败的处理。

尽量避免大量 Redis Key 同时失败(完美)。 Redis 是单线程模型。 如果大量对象同时失败,后续请求可能会频繁出现请求超时问题。 如图所示:

代码java下载文件_java代码_代码jakarta

优化方案:故障时间后可添加允许随机时间。 如下所示:

Redis应尽量使用池方式,而应避免使用直连方式。 直接方式每次都会建立一个TCP连接,而池方式可以减少TCP连接数,减少TCP握手时间,提高响应速度。 以此类推,凡是创建对象需要时间的地方,都可以适当考虑对象池技术。 推荐使用-pool2工具,使用起来比较方便,不需要自己实现。

如果你使用双重检查来实现单例,请记住添加关键字。 因为编译器可能会对我们的代码进行重新排序,双重检查的编译结果会与源代码不一致,并且从多线程调用时可能会出现线程安全问题,这可以帮助我们避免编译器重新排序。

代码jakarta_java代码_代码java下载文件

使用时需要注意的是,该关键字仅保证数据可见性。 仅当状态真正独立于程序中的其他内容时才应使用此方法。

对于频繁的Redis操作,如果操作之间没有顺序连接,并且不需要考虑返回结果的及时性,那么应该尽量使用最好的方式来提高效率。 使用方法如下图:

java代码_代码java下载文件_代码jakarta

如图所示,可以使用方法来提高效率:

java代码_代码jakarta_代码java下载文件

它可以帮助我们批量处理命令,一次返回操作结果,减少TCP交互次数,提高效率。 但是,该方法不能过度使用。 Redis操作结果会缓存在内存中,然后一次性返回给客户端。 该方法取决于内存限制,并且运算结果集不宜太大。

在使用Redis的锁机制时,应该仔细考虑使用范围和使用方法。

如图所示,这段代码利用key是否存在以及是否为1来保证原子操作。 不过这段代码仍然不能保证多线程的安全问题。 如果两个线程A和B同时进入逻辑,且A线程较早获得CPU资源且处理速度较快,则当A线程完成整个方法的逻辑时,B线程仍处于原来的状态位置。 此时线程B获得CPU资源,按照下面的逻辑,就会出现数据重复插入的问题。

java代码_代码jakarta_代码java下载文件

优化的办法就是将ret=xxx这行代码移到if(!…),而if语句中的查询等操作也可以放在if上面,尽可能的减少这个原子操作的时间。

Redis乐观锁也可以用来保证原子操作。 关于Redis乐观锁(CAS)的实现请自行百度等!

使用Kafka时,建议生产者和消费者使用批处理来提高吞吐量,同时还必须考虑批处理失败的后果。 批量失败对结果的影响肯定比单次生产或消费大得多。 不特别推荐使用下面的方法。 虽然程序可以正常运行,但是每次Kafka队列中积累大量数据时,都是通过添加机器来解决。 其实可以从代码角度进行优化,减少机器的使用,提高单机的CPU和内存的使用率。

代码jakarta_java代码_代码java下载文件

使用线程池时要小心选择合适的拒绝策略。

如下图所示,该方法是死循环调用的,所以任务创建速度非常快。 优化前的代码没有拒绝策略,这是默认使用的策略。 下图是优化后的代码。 之前,第一个红色区域没有代码。

java代码_代码java下载文件_代码jakarta

如下图所示,从JDK源码中可以看出,线程池无法处理的任务被放置在无界队列中(size=.),这就产生了一个很大的问题。 如果消耗速度跟不上,内存中就会堆积大量Task,内存占用会迅速增加。 因此,需要针对线程池任务的存储选择合适的拒绝策略。

代码java下载文件_代码jakarta_java代码

比如本题第一张图的第一块代码,如果发生拒绝,就会执行..put(r); 而put是阻塞的,会一直等待,直到Queue中有可用空间,而阻塞的线程就是put进入Task的线程,就是调用线程,这样Queue就不会无限增加。

好了,今天的主题就讲到这里吧,不管如何,能帮到你我就很开心了,如果您觉得这篇文章写得不错,欢迎点赞和分享给身边的朋友。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注