并发
⭐什么是并发,什么是并行:
- 并发:指在同一时间段内,有多个任务在交替执行。
- 并行:指在同一时间段内,有多个任务同时执行。
单核CPU也存在并发问题吗?
单核cpu也是存在并发问题的。
上下文切换
至于什么是上下文切换,简单来说就是任务从保存到再加载执行的过程就是一次上下文的切换。CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。
并发一定比串行快吗?多线程就一定快吗?
- 不一定会快,线程的创建和上下文的切换会导致并发执行的速度比串行慢,当CPU产生浪费比例比较大的时候使用多线程才比较合适。
测试上下文切换的工具:
- Lmbench测量上下文切换的时长
- vmstat测量上下文切换切换的次数
减少上下文切换的方法:
- 无锁并发编程。可以使用一些方法来避免锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据
- CAS算法。Java的Atomic包使用CAS来更新数据,不需要加锁。
- 使用最少线程。避免创建不需要的线程
- 使用协程。在单线程实现多任务的调度,并在单线程里维持多个任务间的切换
死锁
当一个线程竞争资源失败,他会进入阻塞队列并让出CPU,并且不会释放它当前已经持有的任何锁。假设t1、t2分别持有锁1、锁2,t1想要获得锁2而t2想要获得锁1,那么t1、t2都会竞争锁失败,并且互相等待对方释放锁,此时就产生了死锁。
死锁的充要条件
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
- 循环等待条件:在发生死锁时必然存在一个进程等待队列,其中每个进程所占有的资源同时被另一个申请,形成一个进程等待环路。
如何避免死锁
- 避免同一个线程同时获得多个锁
- 变量一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
- 尝试使用定时锁,使用
lock.tryLock(timeout)
来代替使用内部锁机制 - 对于数据库锁,加锁解锁必须在一个数据库连接里,否则会出现解锁失败的情况