上下文切换:cpu分配给线程执行任务的时间就是时间片,每个时间片很短,想要完成任务CPU通过不停地切换线程执行,让我们感觉多个线程是同时执行的,时间片一般是几十毫秒(ms)。CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个 任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这 个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。
因为上下文切换可能导致并发速度慢
减少上下文切换方法:
- 无锁并发编程。多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。
- CAS算法。Java的Atomic包使用CAS算法来更新数据,而不需要加锁。
- 使用最少线程。避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这 样会造成大量线程都处于等待状态。
- 协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。
死锁:是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象
出现死锁的四个条件:
- 互斥,共享资源x和y只能被一个线程占用
- 占用且等待,线程t1已经取得共享资源x,在等待共享资源y的时候,不释放共享资源x(我们可以一次性申请所有的资源,这样就不存在等待了)
- 不可抢占,其他线程不能强行抢占线程ti占有的资源(占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源,这样不可抢占这个条件就破坏掉了。)
- 循环等待,线程t1等待线程t2占有的资源,线程t2等待线程t1占有的资源,就是循环等待(所谓按序申请,是指资源是有线性顺序的,申请的时候可以先申请资源序号小的,再申请资源序号大的,这样线性化后自然就不存在循环了。)
破坏占用且等待条件的最好方式:如果线程要求的条件不满足,则线程阻塞自己,进入等待状态;当线程要求的条件满足后,通知等待的线程重新执行,也就是等待通知机制synchronized中三个方法wait、notify和notifyAll实现此机制
资源限制的挑战:资源限制是指在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源。
