公众号12.10-12.16

标题格
  1、线程的五种状态
  2、Java 8 优化CAS性能
  3、如何对每秒上千场景下的分布式锁高并发优化
  4、并发问题的AQS理解
  5、非公平锁
  6、消息的优缺点、选择哪种
  7、TCC分布式事务

1、线程的五种状态
  1)、新建
  当new创建一个线程,例如new thread(r),线程还没开始运行,处于新建状态。
  2)、就绪
  新建的新线程并不会自动运行,要执行需要调用start()方法创建线程运行的系统资源,返回后,此时线程就处于就绪状态。
  但是处于就绪状态的线程也并不是就能立即执行run()方法。因为线程必须同其他线程竞争CPU时间,获得CPU时间才能运行线程。(线程数>CPU数)
  3)、运行
  当线程获得CPU时间,进入运行状态,执行run()方法。
  4)、阻塞
  线程运行过程中,可能由于很多原因进入阻塞状态:
    1)、线程通过调用sleep方法进入睡眠状态;
    2)、线程试图获得一个锁,但是该锁被其他线程持有;
    3)、线程在等待某个处罚条件;(例如定时启动线程)
    所谓阻塞就是正在运行的线程没有结束,暂时让出CPU,其他处于就绪的线程就获得CPU时 间,进入运行状态。
  5)、死亡
  两个原因导致线程死亡:
    1)、run()方法正常退出而自然死亡;
    2)、一个未捕获的异常终止了run方法而使线程猝死;
    用isAlive返回true,则线程可运行或被阻塞。返回false,则线程死亡或者new状态且不是可运行的。

2、Java 8 优化CAS性能
  1)、什么是CAS
  例如一个多个线程对一个变量不停累加/累减1,例如 private int data = 0; data ++; 当多线程执行就可能会发生错误,结果并不一定会准确。 最开始的解决

  办法是加锁 public synchronized void add() { data ++}; 但是一个简单的Java操作用synchronizes大材小用。 所以现在用了atomic原子类

  private  atomicInteger data = new AtomicInteger(0); data.incrementAndGet(); 该方法即使用了CAS机制。
  CAS(compare and Set):多个线程都获取data当前值,走一个CAS的原子操作,然后所有线程拿当前值比较data的值,相等,则过滤,不相等,则进入

  下一个循环。
  2)、Java 8的优化
  如果线程太多,可能会进入一个无线重复的循环中。所以Java 8推出了分段CAS以及自动分段迁移机制:发现并发线程过多,就会内部分Cell

  数组,每个数组都是一个数值的分段。 然后一部分线程执行分段1,一分部线程执行分段2...减轻了循环的次数。 如果某个Cell的value执行CAS失败,就会

  找其他Cell分段执行CAS操作。

3、如何对每秒上千场景下的分布式锁高并发优化
  如果对一个商品不加锁,就可能出现库存超卖的情况(库存15,2个用户各买10个,没有锁的情况可能出现-5的最终库存)。所以我们可以用:4

  悲观锁、乐观锁、分布式锁、队列串行化、异步队列分散、Redis原子操作等等...
  现在限定了分布式锁,有个问题:如果一套请求-下单需要20毫秒,1秒就只能容许50个用户对商品的排队等候情况(分布式锁),不能做到每秒上千场景。
  解决方法:首先理解Java的ConcurrentHashMap的源码和底层原理,核心就是分段加锁。所以我们可以把1000个商品分成20段库存,客户端  

  1000个请求进服务端的时候,随机分给20段库存,每个分段各自加锁执行...但是某个下单请求,加锁后发现分段库存不足。那么必须释放锁,换以一个分段库存,再测尝试加锁处理。
  这个方法主要缺点就是太复杂

4、并发问题的AQS理解
  AQS(AbstractQueuedSynchronizer,抽象队列同步器)是Java并发包的基础类。ReentrantLock,加锁和解锁的核心组件(ReentrantLock lock = new   ReentrantLock() lock.lock();加锁 lock.unlock() 解锁)。
  AQS对象内部有个变量state(int类型)代表加锁对象,初始值0(加锁状态值=1)。AQS还有个关键变量,记录当前加锁的是哪个线程,初始值null。
  AQS还有一个等待队列,专门放加锁失败的线程(CAS机制加锁机制)。
  一句话总结:就是一个并发包的基础核心组件,实现各种锁,各种同步组件的。

5、非公平锁
  在加锁过程,线程1运行,线程2处于等待队列。 线程1运行结束,结果线程3抢先于线程2进行。这就是非公平锁的简单含义。
  在ReentrantLock lock = new ReentrantLock()默认的就是非公平锁,构造函数中加入true:ReentrantLock lock = new ReentrantLock(true)。
  公平锁原则就是线程3就绪后,会先查看等待队列是否有线程,有就排队。

6、消息的优缺点、选择哪种
  常见的消息插件有Kafka、ActiveMQ、RabbitMQ、RocketMQ...
  优点:
    解耦,使得子系统之间的耦合关系降低,只需要关注消息的发送与接收,不用担心子系统1挂了以后对子系统2产生影响。
    异步,系统直接的数据传输不需要直接请求,直接发送消息,其他系统接收消息,返回,速度大大提高。
    削峰,消息插件控制着请求数量,到达系统的数量/到数据库的数量。
  缺点:系统可用性降低、系统复杂度提高、一致性问题。
  ActiveMQ社区不活跃,要死的节奏。RabbitMQ是用erlang语言写的,很多人不能研究和掌控,但是对于小公司来说没问题。RocketMQ阿里的也可以。大数据领域用Kafka是业内标准。

7、TCC分布式事务
  使用springcloud微服务,也有可能各个服务之间,没有形成一个整体的事务
  分步实现
    1)、try阶段:多个服务之间,在操作的时候对数据库的操作都是一个"预"操作阶段,锁定某个资源,冻结某部分资源等(把改变的数据先存临时表)
    2)、confirm阶段:如果服务全部通过,依靠TCC分布式事务框架来执行---加入一个confirm类,提供一个接口,将刚刚的临时表数据,变为对数

    据库真实的操作。(完成所有逻辑)
    3)、Cancel阶段:如果某个服务挂了---也是提供一个接口,将临时表中的数据,恢复到原数据库中。(回滚所有逻辑)
    该事务适用于同步操作


该随笔分类为公众号笔记,仅做笔记记录,加深记忆以及方便用时查找,非抄袭,非盈利。
参考:纯洁的微笑、石杉的架构笔记、java版web项目、架构师之路、springForAll社区等公众号。

猜你喜欢

转载自www.cnblogs.com/AlmostWasteTime/p/10129438.html