一、多线程
1. 好处
- 充分利用多核cpu
- 防止阻塞
2. 线程安全
也叫并发安全
- 在多线程和单线程下,执行的结果一致,则是安全
- golang措施:channel队列 和 加锁
- Channel: 线程安全队列, 在c++中有BlockingQueue
- 该加锁就加锁,性能消耗没那么大
3. 线程池
3.1. Why
- 对创建的线程进行复用, 避免频繁的创建和销毁线程
- 灵活控制并发数目。
3.2. 线程数
- 高并发,执行时间短:线程数设置为cpu数+1, 减少线程上下文切换
- 并发低,执行时间阻塞在IO: 加大线程数, 充分利用cpu
- 并发低,执行时间主要在cpu运算: 线程数设置为cpu数+1, 减少线程上下文切换
- 高并发,执行时间长:考虑优化。 缓存、服务器增加、中间件对服务进行解耦
二、一致性、事务
事务: 一个操作序列,要么都执行成功,要么都不执行。ACID特性
1. 事务的隔离级别
mysql的隔离级别是repeatable read, 但是同时解决了幻读(select 范围语句),通过加锁
1.1. read uncommitted
- 只解决并发写
- 脏读问题, 看到了还未提交的数据
1.2. Read commit
- 一个事务提交后,另外的事务才能读
- 一个事务(买单), 读到两个不同的数据。
- 不可重复读问题
1.3. Repeatable read
- 事务开启,不允许其他事务对数据进行update操作
- 幻读问题: insert操作, 打流水单时
1.4. Serializable
串行执行, 解决幻读。 性能低!
2. 幂等性
多次重复操作无影响
3. 锁
3.1. 互斥锁
一次只能有一个线程获取,其他线程等待
3.2. 读写锁
只有读者:多线程同时读 有写时:一个线程写时,不能读,也不能写
3.3. 死锁问题
golang场景下,既是释放, defer xxx.unlock()
3.4. 乐观锁和悲观锁(机制)
修改数据的三步骤: 1. 取 2. 改 3.写
- 乐:总认为不会有并发问题, 所以不加锁,在写时判断, 重试
- 悲: 怎么着都先加把锁,然后123
4. Mysql
并发更新问题:http://www.topthink.com/topic/815.html (1. 合成一条语句; 2. 事务; 3. 乐观锁)