并发

Posted by jabin on December 1, 2018

一、多线程

1. 好处

  1. 充分利用多核cpu
  2. 防止阻塞

2. 线程安全

也叫并发安全

  1. 在多线程和单线程下,执行的结果一致,则是安全
  2. golang措施:channel队列 和 加锁
  3. Channel: 线程安全队列, 在c++中有BlockingQueue
  4. 该加锁就加锁,性能消耗没那么大

3. 线程池

3.1. Why

  1. 对创建的线程进行复用, 避免频繁的创建和销毁线程
  2. 灵活控制并发数目。

3.2. 线程数

  1. 高并发,执行时间短:线程数设置为cpu数+1, 减少线程上下文切换
  2. 并发低,执行时间阻塞在IO: 加大线程数, 充分利用cpu
  3. 并发低,执行时间主要在cpu运算: 线程数设置为cpu数+1, 减少线程上下文切换
  4. 高并发,执行时间长:考虑优化。 缓存、服务器增加、中间件对服务进行解耦

二、一致性、事务

事务: 一个操作序列,要么都执行成功,要么都不执行。ACID特性

1. 事务的隔离级别

mysql的隔离级别是repeatable read, 但是同时解决了幻读(select 范围语句),通过加锁

1.1. read uncommitted

  1. 只解决并发写
  2. 脏读问题, 看到了还未提交的数据

1.2. Read commit

  1. 一个事务提交后,另外的事务才能读
  2. 一个事务(买单), 读到两个不同的数据。
  3. 不可重复读问题

1.3. Repeatable read

  1. 事务开启,不允许其他事务对数据进行update操作
  2. 幻读问题: insert操作, 打流水单时

1.4. Serializable

串行执行, 解决幻读。 性能低!

2. 幂等性

多次重复操作无影响

3. 锁

3.1. 互斥锁

一次只能有一个线程获取,其他线程等待

3.2. 读写锁

只有读者:多线程同时读 有写时:一个线程写时,不能读,也不能写

3.3. 死锁问题

golang场景下,既是释放, defer xxx.unlock()

3.4. 乐观锁和悲观锁(机制)

修改数据的三步骤: 1. 取 2. 改 3.写

  1. 乐:总认为不会有并发问题, 所以不加锁,在写时判断, 重试
  2. 悲: 怎么着都先加把锁,然后123

4. Mysql

并发更新问题:http://www.topthink.com/topic/815.html (1. 合成一条语句; 2. 事务; 3. 乐观锁)