上下文切换开销
cpu会给每个线程分配时间片来执行线程,时间片是cpu分配给线程的执行时间,时间片非常的短,是几十毫秒级别的,cpu会通过不断地切换时间片来执行各个线程,这就让人感觉多个线程是并行执行的,其实还是有一定先后顺序的。线程时间片的轮转机制使即使是单核cpu也能实现线程执行。
cpu通过时间片分配算法来循环执行任务,当前任务时间片执行完后会切换到下一个时间片,但是切换前要保存上一个任务的执行状态,为了下次轮转到该任务时继续执行。所以任务从保存到再加载的过程中就是一次上下文切换。这种上下文切换过程会影响多线程的执行速度。
所以少量任务的多线程方式不一定快,因为上下文的切换开销。
减少上下文切换
减少上下文切换的方法有:
-
无锁并发编程
无锁并发编程是,在多线程竞争锁时,会引起上下文切换,所以多线程处理处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法器模分段,不同的线程处理不同的数据段。 -
CAS算法
CAS算法,JAVA的Atomic包使用CAS算法来更新数据,而不需要加锁。 -
使用最少线程
使用最少线程,避免创建不需要的线程,比如任务很少,就不用创建很多线程来处理,否则将造成大量线程处于等待状态。 -
使用协程
在单线程实现多任务调度,并在单线程里维持多个任务间的切换。
死锁
使用锁机制时经常会出现死锁的情况,一旦死锁,就会造成系统功能不可用。
关于死锁的详细说明可以查看 https://www.jianshu.com/p/b42fc3a1a05f
避免死锁的方法:
- 避免一个线程同时获得多个锁
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
- 尝试使用定时锁,使用lock.tryLock(timeout)来代替使用内部锁机制
- 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。