作者:叶韵 | 来源:互联网 | 2024-10-20 13:33
这个写出来,纯属自娱自乐,以后还得再改正。
什么是并发编程?
并发编程目的是为了让程序运行的更快(也不是线程越多,越快,这里会遇到很多的问题,不如上下文切换问题,死锁的问题,以及受限于硬件和软件的资源限制)
上下文切换(任务从保存到再加载的过程)(类似于我们玩的单机游戏的存档,可以不同的人来玩一样)
什么是上下文切换?
是指CPU从一个进程或者线程切换到另一个进程或者线程
剩下文切换的步骤?
1 挂起一个进程或者线程,将这个线程在cpu中的状态(对,没错这个状态就叫做上下文)存储在内存中的某处 2 在线程中检索写一个线程的上下文并在CPU寄存器中恢复3跳转到上一个线程被中断的代码行(我想这也就是需要程序计数器和寄存器的原因,抱歉寄存器我现在都还没搞懂)
即使是单核CPU也是支持多线程执行代码的,CPU通过给每个线程分配CPU时间片(CPU分配给各个线程的时间)来实现这个机制,因为时间片非常短,所以CPU通过不停的切换线程线程执行,让我们感觉多个线程是同时执行的,时间片一般是几十毫秒。
CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换会这个任务,可以再加载这个任务的状态,所以任务从保存到再加载的过程就是一次上下文切换。
上下文的切换是会影响效率(任务的执行时间)的,同样上下文切换也会影响多线程的执行速度。
减少上下文切换实战
类似于上面的这个例子serial()方法是单线程的执行时间测试concurrency()是多线程的时间效率的测试。
那么当操作不超过百万次时,并发会比串行的执行速度要慢,为什么会产生这种情况,因为线程有创建和上下文切换的开销。
那我们就来测试一下上下文切换的次数和时间的长短 具体来看看
从cs可以看出上下文切换,每隔一秒就要切换1000多次。也就是切换一次需要1ms喽,也就是说当我们执行一段程序时,上下文在不停的切换,增加了我们的执行书时间。
如何减少上下文的切换
具体有(无锁并发编程,CAS算法,使用最少线程和使用协程)
无锁并发编程:多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照HaSh算法取模分段,不同的线程处理不同段的数据(这里我不太清楚他指的数据是什么数据?一般for循环不都是每一一个数据吗?(这里应该指的是多核处理器执行吧))
CAS算法:java的Atomic包使用CAS算法来更新数据,而不需要加锁。
使用最少线程:这个比较简单,就是避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量的线程都处于等待状态(我就想不通,难道处于等待状态的线程也会浪费时间?想通了,当线程创建的时候是NEW状态,然后创建完成之后就成了Runnable状态,这个转换是需要时间的,这里的比如执行一个任务,我们有两个线程A和B的话,那么这个任务肯定就要不就是线程A执行 要不就是线程B执行,切换频率肯定小,而且因为我们的处理器处理的线程是有限的,如果100个的话,那么谁做还不确定,有空闲的线程,在等待回调消息之后有可能就直接切换别的线程进行执行了,所以上下文切换比较多)。
协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换(哇这什么鬼,难道在绕口令吗,还是我太菜了 其实是当一个线程执行一个任务的时间片段到了之后,然后需要自己手动中断,然后保存上下文的状态,然后让这个线程再继续执行下面的直到任务结束,相当于单任务的多线程单核执行吧 ,而且是和多线程一块进行,互不影响)。
死锁
锁我们经常使用,但是它也会给我们带来一些困扰,那就是可能会引起死锁,一旦产生死锁,就会造成系统功能不可用。
A等待B释放B等待A释放 造成无限死循环 就会造成死锁
当然显示情况中我们并不会写出这样的代码,但是在我们写的过程中,比如线程A拿到了锁,但是因为一些异常,没有释放这个锁,或者说,线程A拿到了一个数据库锁,释放锁的时候抛出了异常,没释放掉,一旦出现死锁,业务就得停止,那么就只能通过dump线程查看到底是哪个线程出现了问题。
通过dump线程查看到的结果,他会告诉你是哪个类的多少行引起了死锁,对应我们上边的就是,42和31
下面我们来介绍避免死锁的几个常见方法
避免一个线程同时获取多个锁
避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
阐释使用定时锁使用lock.tryLock(timeout)来替代使用内部锁机制
对于数据库加锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
资源限制的挑战
1什么是资源限制
资源限制是指在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源,例如服务器的带宽只有2MB/S,某个资源的下载速度是1MB/S每秒,系统启动10个线程下载资源,下载速度不会变成10Mb每秒,所以在进行并发编程时,要考虑这些资源的限制,硬件资源限制有带宽的上传/下载速度,硬盘读写速度和CPU的处理速度,软件资源限制有数据库的连接和SOCKET连接数等等。
2资源限制引发的并发问题
在并发编程的过程中,将代码执行加快的原则是将代码中串行执行的部分编程并发编程
但是如果将某段串行的代码并发执行,因为受限于资源仍然在串行执行,这时候程序不仅不会加快执行,反而会变更慢,因为增加了上下文切换和资源调度时间。
3如何解决资源限制问题
对于硬件资源的限制,我们可以考虑集群并行程序,既然单机的资源有限制,那就在多机上进行运行。
对于软件资源限制,可以考虑使用资源池将资源复用,比如使用连接池连接数据库和socket连接复用,