线程
互斥锁
线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即:数据几乎同步会被多个线程占用,造成数据混乱,即所谓的线程不安全。
为了解决这个问题, 引入了互斥锁的概念,一个资源只能被一个线程执行。
坏处: 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
锁的致命问题: 死锁
死锁
若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果是谁也不愿先解锁,互相干等着,程序无法执行下去,这就是死锁。
image.png
造成死锁的原因可以概括成三句话:
- 当前线程拥有其他线程需要的资源
- 当前线程等待其他线程已拥有的资源
- 都不放弃自己拥有的资源
死锁的产生条件:
- 互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
- 请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
- 不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
- 环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
阻塞
由于资源短缺,而造成的部分程序暂停等待 image阻塞的原因
1、线程执行了Thread.sleep(int millsecond);方法,当前线程放弃CPU,睡眠一段时间,然后再恢复执行
2、线程执行一段同步代码,但是尚且无法获得相关的同步锁,只能进入阻塞状态,等到获取了同步锁,才能回复执行
3、线程执行某些IO操作,因为等待相关的资源而进入了阻塞状态。比如说监听system.in,但是尚且没有收到键盘的输入,则进入阻塞状态。
4、线程执行了一个对象的wait()方法,直接进入阻塞状态,等待其他线程执行notify()或者notifyAll()方法。
活锁
image活锁指的是任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试,失败,尝试,失败。 活锁和死锁的区别在于,处于活锁的实体是在不断的改变状态,所谓的“活”, 而处于死锁的实体表现为等待;活锁有可能自行解开,死锁则不能。
饥饿
image这是个独木桥(单进程),桥上只能走一个人,B来到时A在桥上,B等待;而此时比B年龄小的C来了,B让C现行(A走完后系统把进程分给了C),C上桥后,D又来了,B又让D现行(C走完后系统把进程分个了D)以此类推B一直是等待状态.
原因
1、优先级导致
2、同步锁导致的,一个进程的等待线程会有多个,锁释放后,随机竞争,和os调度有关,这就会存在一种可能,某个线程运气极差,每次抢锁都没抢到。 而且新的线程还在不断地进入等锁的队列,从而导致这个线程就几乎是一直处于等待中。 这就使得这个“悲催”的线程就处于“饥饿”中,而且还会悲惨的“饿死”。
3、我们知道notify()方法会唤醒对象条件队列中等待的某个线程,但是,可惜这个唤醒是无序的(和VM调度,OS调度有关,甚至底层是随机选取一个,更甚至就是队列中的第一个)。 而如果,条件队列不断有新的线程进入,或者在唤醒的那一刻,刚好有其他线程抢入,那都可能导致某个运气不好的线程迟迟不能被唤醒。 对这个线程来说,就是进入一种“饥饿”的状态,甚至还会有“饿死”的风险。
同步,异步,阻塞,非阻塞
1、同步: 多个任务之间有先后顺序执行,一个执行完下个才能执行
2、异步: 多个任务之间没有先后顺序,可以同时执行,有时候一个任务可能要在必要的时候获取另一个同时执行的任务的结果,这个就叫回调!
3、阻塞: 如果卡住了调用者,调用者不能继续往下执行,就是说调用者阻塞了
4、非阻塞: 如果不会卡住,可以继续执行,就是说非阻塞的
同步异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。
python的多进程和多线程对比
程序为存储在磁盘上的可执行文件,当把程序加载到内存中并被操作系统调用,则拥有了生命周期,进程即为运行中的程序。
一个进程可以并行(类似于异步)运行多个线程,每个线程执行不同的任务,也就是说线程是进程的组成部分。
当一个进程启动时至少要执行一个任务,因此至少有一个主线程,由主线程再创建其他的子线程。
多线程的执行方式和多进程相似,由操作系统在多个线程之间快速切换,让每个线程都短暂的交替运行,看起来像同时执行一样。当然,多核CPU可真正意义上实现多线程或多进程的同时执行。
进程和线程之间存在不同的特点。
每个进程拥有自己的地址空间、内存和数据栈,由操作系统管理所有的进程,并为其合理分配执行时间。
由于进程间资源相互独立,不同进程之间需要通过IPC(进程间通信)
方式共享信息,但单个进程崩溃时不会导致系统崩溃。
而多线程是在同一个进程下执行的,共享同一片数据空间,相比于进程而言,线程间的信息共享更加容易,但当一个线程崩溃时会导致整个进程崩溃
补充: 并发与并行:
并发: 不会在同一时刻同时运行,存在交替执行的情况,交替做不同事的能力
并行: 同一时刻多个任务同时运行,同时做不同事的能力
程序需要执行较多的读写、请求和回复任务的需要大量的IO操作,IO密集型操作使用并发更好。
CPU运算量大的程序,使用并行会更好
python中进程与线程的使用场景?
多进程适合在CPU密集操作(cpu操作指令比较多,如位多的的浮点运算)。
多线程适合在IO密性型操作(读写数据操作比多的的,比如爬虫)
GIL链接