首页 课程 师资 教程 报名

Java基础学习:Java并发程序设计教程

  • 2020-04-28 12:47:11
  • 1928次 动力节点

    1.服务接口的幂等设计

    幂等:每次请求重复调用的结果都是一样的。

    分布式服务中的提交接口一般都需要进行幂等校验。例如做支付接口,如果一笔支付在网络异常时进行两次,或者更多次调用。没有控制幂等的设计,那么可能会导致进行多次支付,而系统中只有一笔订单,造成的影响不言而喻。

    幂等性一般可以用一个请求号和请求来源来记录,将请求号和请求来源存入redis里面,如果有重复的过来,就直接拒绝,也可以针对请求和请求来源做唯一索引,这样带有重复数据提交过来的时候就会落库失败。

    当然也可能会有不同的请求号的重复提交,比如用户第1次申请的时候,卡住了,然后用户返回之后可以点击第2次申请,这样就会导致重复点击了两次支付。这样一般的做法就是添加一个乐观锁机制,根据用户这一笔钱的支付状态,或者是用户的版本来进行比对,如果比对失败,说明可能是重复的支付,那么就直接拒绝掉。

    2.mq分布式系统的应用,以及mq消息不丢失的设计

    mq一般用来作为分布式系统的解耦合调用,系统的削峰填谷(入队队列满之后,拒绝新的事件入队,也可以适当避免系统低峰时间请求数量太少了而导致的系统资源浪费),系统的消息分发,做延迟队列来处理一些定时的任务等。

    mq的类型也是多种多样,如何选型也是比较关键的因素。例如最近很火的kafka,因为它的高吞吐量,零拷贝快速持久化消息著称;rabbitmq,以它对多种消息传输协议,支持灵活的消息路由,负载均衡策略和保证消息不丢失的策略而广受企业追捧;activemq,以它支持多种语言客户端,能够实现多种高级应用闻名;rocketmq,能够支持大量的消息堆积,精准控制消息顺序,消息过滤等多种功能......不同的mq应用场景也不一样,诸君需要根据系统属性来合理选择。

    mq中如何确保消息不丢失?以rabbitmq为例。如果是生产者丢失消息,没有正确的发送到mq中。为了确保消息不丢失,mq生产者发送的时候要设置持久化参数,那么mq接收到生产者传送过来的消息时,会首先把mq消息,持久化到磁盘,持久化完成之后才会返回,给生产者一个ack,生产者收到这个ack之后,说明消息已经成功传输到mq上,否则生产者将会重复传送这一条消息。消息传到mq上以后,还要确保消息能够成功的发送给消费者,且消费者能够成功的处理完消息,因此可以设置消费者处理消息完成之后,再返回ack到mq,mq收到消费者回传的ack之后才会将消息移出队列,否则则会重复发送。

    3.redis分布式系统应用

    数据缓存(通过redis缓存的数据可以更快的进行访问,保证db不会因为压力太大出现异常,同时可以增强系统吞吐量,但是需要准确的控制缓存数据与db数据之间的一致性,否则可能会造成脏读。如何保证缓存命中率是个比较复杂的事情,需要根据系统属性来对缓存属性进行设计,同时也要兼顾到缓存穿透一类的问题)。

    分布式锁(使用redis的setnx函数,利用此函数的原子特性,将需要锁的对象唯一性的一些字段添入其中,设置过期时间。其他线程过来,发现对象被锁之后,采用自旋的方式重复获取对象一段时间,如果占用对象的线程释放对象之后便可以获取到对象锁,否则直接抛出失败)。

    分布式幂等性接口(同样使用setnx函数的特性,根据来源传输的唯一性请求号来进行加锁)。

    处理队列(类似于用redis来实现一个mq队列的功能,不过没有mq那么完全的一个保证消息不丢失的机制,需要衡量利弊使用)。

    bitmap(用来记录一些大数据位的数据结构,可以用来做布隆过滤器,进行缓存条件的过滤,可以防止缓存穿透,缓存击穿)。

    4.线程及线程池的使用,种类,以及线程池的设计

    放一张线程状态转换图(清晰明了,相信不用我多做解释):

Java基础学习:Java并发程序设计教程

    线程池可以分为四大类(Executors工具类),单例线程池(顾名思义,是初始化核心线程和最大线程数只有一的线程池,一般用来对线程进入的先后顺序进行依次执行。),固定线程池(固定的核心线程数和最大线程数,可以根据机器的核载量来决定线程池的大小),缓存线程池(初始化核心线程数为0,阻塞队列为同步的,且最大线程数不做限制的一个线程。这类线程时可以根据具体请求来决定线程池数量的大小,收放自如,但是不做最大线程数的限制,但是可能会引起机器压力过大线程数过多等问题),定时任务线程池(创建一个定长的,可以按周期定时执行的线程池)

    线程池初始化的几个参数:如果选择用自定义线程池ThreadPoolExecutor来初始化线程池(这种方式也是阿里推荐使用的,直接用Executors工具类可能会导致),需要注意的几个参数(核心线程数,最大线程数,队列选型,拒绝策略)。队列类型:ArrayBlockingQueue,PriorityBlockingQueue:有界队列,队列满时会创建新线程直到最大线程数,队列满时按照拒绝策略返回;LinkedBlockingQueue:无界队列,队列不限制大小,不过需要注意如果队列一直增加会导致oom;SynchronousQueue:同步队列,一般用于cache类型的线程池;拒绝策略:AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。DiscardPolicy:也是丢弃任务,但是不抛出异常。DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务。CallerRunsPolicy:由调用线程处理该任务。

 以上就是动力节点java培训机构的小编针对“Java基础学习:Java并发程序设计教程”的内容进行的回答,希望对大家有所帮助,如有疑问,请在线咨询,有专业老师随时为你服务。

选你想看

你适合学Java吗?4大专业测评方法

代码逻辑 吸收能力 技术学习能力 综合素质

先测评确定适合在学习

在线申请免费测试名额
价值1998元实验班免费学
姓名
手机
提交