线程等待和线程守护
线程等待:
使用的是join方法,其功能是指等待某个线程执行完成后主线程才会继续执行
线程守护:
使用的是setDaemon方法,其功能是指当主线程执行结束,不管调用该方法的进程有没有结束,都会强制结束
线程守护的设置,一定是在开启线程之前
threading模块中提供的方法
threading.currentThread()
返回当前线程对象
threading.enumerate()
返回一个包含正在运行的线程list
threading.activeCount()
返回正在运行的线程数量
多线程使用全局变量
多线程开发时,共享全局变量,会带来资源的竞争,也就会出现数据不安全
问题产生的原因:多个线程同时访问同一个资源,我们没有对数据进行保护,造成数据破坏,导致线程的结果不可预期,这种现象称为数据不安全
解决方法:同步处理,加锁
互斥锁
某一个线程需要修改数据前,先将其锁定,此时资源属于锁定状态,其它线程是不能对其进行操作的,直到当前线程将锁释放,其它线程将当前数据进行锁定,才可以进行操作,这就保证了每次对此数据进行操作的只有一个线程,保证了数据的安全,但是牺牲了效率
锁的好处:确保了某段关键代码只能由一个线程从头到尾完整地执行
锁的坏处:阻止了多线程并发执行,包含锁的某段代码实际上只能单线程执行,效率大大下降
由于可以出现多个锁,不同线程有不同的锁,就可能会出现死锁的发生
死锁:
在多个线程共享资源的时候,如果两个线程分别占有一部分资源,并且同时等待对方的资源,
就会出现死锁现象
如果锁之间相互嵌套,就有可能出现死锁,因此尽量不要出现锁之间的嵌套
解决死锁:
可以给锁设置blocking=False不阻塞
例:
import threading
import time
def func1():
print("t1开始执行")
if t1_lock.acquire():
print("t1获取t1锁")
time.sleep(0.1)
if t2_lock.acquire(blocking=False):
print("t1获得t2锁")
t2_lock.release()
print("t1释放t2锁")
t1_lock.release()
print("t1释放t1锁")
def func2():
print("t2开始执行")
if t2_lock.acquire():
print("t2获取t2锁")
time.sleep(0.1)
if t1_lock.acquire():
print("t2获取了t1锁")
t1_lock.release()
print("t2释放了t1锁")
t2_lock.release()
print("t2释放了t2锁")
if __name__ == '__main__':
# 创建t1锁
t1_lock = threading.Lock()
# 创建t2锁
t2_lock = threading.Lock()
t1 = threading.Thread(target=func1)
t2 = threading.Thread(target=func2)
t1.start()
t2.start()
队列
队列的核心就是先进先出,就如排队一样
python中创建队列使用了queue模块
优先级队列