第三十三天- 线程创建、join、守护线程、死锁
1.线程,线程创建
概念:在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程,线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程,车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线。流水线的工作需要电源,电源就相当于cpu。
所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。
创建:
线程创建方式一:
1 from multiprocessing import Process 2 from threading import Thread 3 4 5 def func(n): 6 print('xxxxx') 7 print('>>>',n) 8 9 10 if __name__ == '__main__': 11 12 # p = Process(target=func,args=(1,)) 13 # p.start() 14 15 t = Thread(target=func,args=(1,)) # 直接创建 16 t.start() 17 18 print('主线程结束')
View Code
面向对象创建:
1 from threading import Thread 2 3 4 # 面向对象创建 5 class Mythread(Thread): # 继承Thread父类 6 7 def __init__(self,xx): 8 super().__init__() 9 self.xx = xx 10 11 def run(self): # 必须有run,覆盖父类run中的pass 12 print(self.xx) 13 print('我重置父类方法') 14 15 def func1(self): # 写其他方法 16 print('我是func1') 17 18 19 if __name__ == '__main__': 20 21 t1 = Mythread('xx') 22 t1.start() # 默认执行run 23 t1.func1() # 调用其他方法 24 # 25 26 from multiprocessing import Process 27 from threading import Thread
View Code
2.Thread类方法
join方法:
主线程等待join子线程执行完毕后才执行
1 import time 2 from threading import Thread 3 4 5 def func(n): 6 time.sleep(n) 7 print('我是子线程') 8 9 10 if __name__ == '__main__': 11 12 t = Thread(target=func,args=(1,)) 13 t.start() 14 15 t.join() # 等待子线程执行结束 16 print('我是主线程,子线程结束再执行我')
join
其他方法:
1 '' 2 Thread实例对象的方法 3 # isAlive(): 返回线程是否活动的。 4 # getName(): 返回线程名。 5 # setName(): 设置线程名。 6 7 threading模块提供的一些方法: 8 # threading.currentThread(): 返回当前的线程变量。 9 # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 10 # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果 11 '''
1 import time, threading 2 from threading import Thread, current_thread 3 4 5 def func(): 6 time.sleep(2) 7 print('子线程,名字是:', current_thread().getName()) # 返回线程名 8 print('子线程,ID是:', current_thread().ident) # 返回线程id 9 10 11 if __name__ == '__main__': 12 13 for i in range(10): 14 t = Thread(target=func, ) 15 t.start() 16 17 print(threading.enumerate()) # 返回一个包含正在运行的list 18 print(threading.activeCount()) # 返回正在运行的线程数量,等同len(threading.enumerate()) 19 20 print('主线程结束')
其他方法示例
3.守护线程、事件
守护线程:
主进程结束,守护进程跟着结束,再执行非守护进程
主线程要等待所有非守护线程运行结束才会结束(因为他们属于同一进程)
需注意:运行结束并非终止运行
xxx.setDaemon(True) 或者 xxx.daemon = True
1 import time 2 from threading import Thread 3 from multiprocessing import Process 4 5 6 def func1(): 7 time.sleep(3) 8 print('任务1结束') 9 10 11 def func2(): 12 time.sleep(2) 13 print('任务2结束') 14 15 16 if __name__ == '__main__': 17 18 # p1 = Process(target=func1,) 19 # p2 = Process(target=func2,) 20 # # p1.daemon = True 21 # p2.daemon = True 22 # p1.start() 23 # p2.start() 24 # 25 # print('主进程结束') 26 27 t1 = Thread(target=func1,) 28 t2 = Thread(target=func2,) 29 # t1.setDaemon(True) # 只打印出 主线程和t2 因为t2时间比t1小 30 t2.setDaemon(True) # 会正常打印出所有 因为t1时间大于t2 31 t1.start() 32 t2.start() 33 34 print('主线程结束')
守护线程与守护进程
事件:
event.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
1 import time 2 from threading import Event 3 4 e = Event() # 默认false状态 5 print(e.isSet()) # 事件当前状态 6 7 e.set() # 改变成Ture 8 print(e.isSet()) 9 10 print('稍等...') 11 # e.clear() # 将e的状态改为False 12 e.wait() # 如果 event.isSet()==False将阻塞线程 13 14 if e.isSet() == True: 15 time.sleep(1) 16 print('滴滴滴,上车吧...')
事件代码示例
4.线程间数据问题
开启一个线程所需要的时间要远小于开启一个进程
1 import time 2 from multiprocessing import Process 3 from threading import Thread 4 5 6 def func(i): 7 return '我是任务%s'%i 8 9 10 if __name__ == '__main__': 11 12 # 多线程 13 t_list = [] 14 t_start_time = time.time() 15 for i in range(10): 16 t = Thread(target=func,args=(i,)) 17 t_list.append(t) 18 t.start() 19 20 [tt.join() for tt in t_list] 21 t_end_time = time.time() 22 t_dif_time = t_end_time - t_start_time 23 24 # 多进程 25 p_list = [] 26 p_start_time = time.time() 27 for i in range(10): 28 p = Process(target=func,args=(i,)) 29 p_list.append(p) 30 p.start() 31 32 [pp.join() for pp in p_list] 33 p_end_time = time.time() 34 p_dif_time = p_end_time - p_start_time 35 # 结果受cpu影响 36 37 print('多线程耗时:',t_dif_time) 38 print('多进程耗时:',p_dif_time) 39 print('主线程结束') 40 41 ''' 42 多线程耗时: 0.0020008087158203125 43 多进程耗时: 0.4188823699951172 44 '''
多线程和多进程效率对比
线程之间共享进程资源(全局变量在多个线程之间共享),但也会导致数据不但全问题
1 import time 2 from threading import Thread 3 4 num = 100 5 6 def func(): 7 global num 8 tep = num # tep替换 模拟多步操作 9 time.sleep(0.001) # 模拟延迟 10 tep -= 1 11 num = tep 12 13 14 if __name__ == '__main__': 15 16 t_list = [] 17 for i in range(100): 18 t = Thread(target=func,) 19 t_list.append(t) 20 t.start() 21 22 [tt.join() for tt in t_list] 23 24 print('主线程的num',num) # 打印出不是100可知数据是共享的 25 26 # 理论上应该是0,但多线程是并发执行的,会出现上一个线程还在运算中时,下一个线程并未等待它返回值 27 # 也拿了原来的值进来运算,所以打印出了91,92,93不等,可知多线程数据是不安全的 28 ''' 29 主线程的num 92 30 '''
验证多线程之间数据共享 数据不安全问题
加锁解决多线程数据不安全问题
1 import time 2 from threading import Thread,Lock 3 4 num = 100 5 def func(lock,i): 6 global num 7 lock.acquire() # 加锁 8 9 tep = num 10 time.sleep(0.001) # 模拟延迟 11 tep -= 1 12 num = tep 13 14 lock.release() # 释放 15 16 17 if __name__ == '__main__': 18 t_list = [] 19 lock = Lock() 20 for i in range(100): 21 t = Thread(target=func,args=(lock,i)) 22 t_list.append(t) 23 t.start() 24 25 [tt.join() for tt in t_list] 26 print('主线程num',num) 27 28 ''' 29 主线程num 0 30 '''
Lock
信号量Semaphore
1 import time,random 2 from threading import Thread,Semaphore 3 4 5 def func(i,s): 6 s.acquire() 7 print('%s张烧饼'%i) 8 time.sleep(random.randint(1,3)) 9 s.release() 10 # 出来一个进去一个 始终6个 最后不足6个就都进来了 11 12 13 if __name__ == '__main__': 14 s = Semaphore(6) # 与Lock类似,不过可限制最大连接数,如这里同时只有6个线程可以获得semaphore 15 for i in range(28): 16 t = Thread(target=func,args=(i,s,)) 17 t.start()
Semaphore
5.死锁和递归锁
死锁现象:有多个锁时,双方互相等待对方释放对方手里拿到的那个锁导致死锁
1 import time 2 from threading import Thread,Lock 3 4 5 def func1(lock_A,lock_B): 6 lock_A.acquire() 7 print('张全蛋拿到了A锁') 8 time.sleep(0.5) 9 lock_B.acquire() 10 print('张全蛋拿到了B锁') 11 lock_B.release() 12 lock_A.release() 13 14 15 def func2(lock_A,lock_B): 16 lock_B.acquire() 17 print('赵二狗拿到了B锁') 18 lock_A.acquire() 19 print('赵二狗拿到了A锁') 20 lock_A.release() 21 lock_B.release() 22 23 24 if __name__ == '__main__': 25 26 lock_A = Lock() 27 lock_B = Lock() 28 t1 = Thread(target=func1,args=(lock_A,lock_B,)) 29 t2 = Thread(target=func2,args=(lock_A,lock_B,)) 30 t1.start() 31 t2.start()
死锁现象
递归锁:RLock
RLock管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。
1 # 递归锁解决死锁现象 2 import time 3 from threading import Thread,Lock,RLock 4 5 6 def func1(lock_A,lock_B): 7 lock_A.acquire() 8 print('张全蛋拿到了A锁') 9 time.sleep(0.5) 10 lock_B.acquire() 11 print('张全蛋拿到了B锁') 12 lock_B.release() 13 lock_A.release() 14 15 16 def func2(lock_A,lock_B): 17 lock_B.acquire() 18 print('赵二狗拿到了B锁') 19 lock_A.acquire() 20 print('赵二狗拿到了A锁') 21 lock_A.release() 22 lock_B.release() 23 24 25 if __name__ == '__main__': 26 27 # lock_A = Lock() 28 # lock_B = Lock() 29 lock_A = lock_B = RLock() 30 t1 = Thread(target=func1,args=(lock_A,lock_B,)) 31 t2 = Thread(target=func2,args=(lock_A,lock_B,)) 32 t1.start() 33 t2.start()
递归锁解决死锁现象
转载于:https://www.cnblogs.com/xi1419/p/10061053.html
第三十三天- 线程创建、join、守护线程、死锁相关推荐
- 利用线程池为线程创建一个守护线程
主线程: public class MainThread implements Callable {SimpleDateFormat sdf =new SimpleDateFormat("y ...
- python多线程threading之阻塞线程(join)线程同步和守护线程(setDaemon(True))实例详解
一.多线程(主线程和子线程同时执行) 1.主线程是程序本身,看不到的,主线程和子线程没有依赖关系,同步执行的,若主线程先执行完,会等子线程执行完毕,程序结束 2.启动一个线程就是把一个函数传入并创建T ...
- 线程安全、守护线程、join()
1. 线程安全 多个线程在访问同一个对象的时候不需要其他额外的同步手段或措施就能保证该对象被正确的访问并产生正确的执行结果.那么这个对象就是线程安全的. 线程安全的代码必须具备一个特征:代码本身封装了 ...
- 多线程、并发/并行、自定义线程类、线程安全、守护线程、定时器、线程状态、线程池
目录 进程和线程: 进程: 线程: 多线程的好处: 线程调度: 分时调度: 抢占式调度: 并发与并行: 线程的生命周期: 实现线程的两种基本方式(还有第三种): 创建Thread线程类: 创建Runn ...
- 守护线程和非守护线程
直觉上来讲,守护线程和main相关 Java中有两种线程,一种是用户线程,另一种是守护线程. 用户线程是指用户自定义创建的线程,主线程停止,用户线程不会停止(另一条执行路径) 守护线程当进程不存在或主 ...
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括: 1. 线程优先级的介绍 2. 线程优先级的示例 3. 守护线程的示例 转载请注明出处:http://www.cnblogs.com/s ...
- 守护线程与非守护线程
Java中有两种线程,一种是用户线程,另一种是守护线程. 用户线程是指用户自定义创建的线程,主线程停止,用户线程不会停止 守护线程当进程不存在或主线程停止,守护线程也会被停止. 使用setDaemon ...
- java的守护线程与非守护线程
守护线程最典型的应用就是GC,它是一个很好的守护者. 最近重新研究Java基础知识,发现以前太多知识知识略略带过了,比较说Java的线程机制,在Java中有两类线程:User Thread(用户线程) ...
- Java中的守护线程和非守护线程(转载)
<什么是守护线程,什么是非守护线程> Java有两种Thread:"守护线程Daemon"(守护线程)与"用户线程User"(非守护线程). 用户线 ...
- 多线程基础-守护线程与非守护线程
守护线程与非守护线程 1.线程分类: 2.程序线程: 3.主线程与非守护线程 4.主线程与守护线程 5.主线程.守护线程.非守护线程 6. java虚拟机是如何退出的? 1.线程分类: 守护线程 非守 ...
最新文章
- 谷歌“验光师”AI算法,让可控核聚变早日成真!
- [脑海成像]科学家利用动态电极绕过眼睛直接刺激大脑,在盲人脑海画出字母
- C# 使用正则表达式去掉字符串中的数字
- Qt Creator在问题窗格中显示任务列表文件
- 推荐10款非常有用的 Ajax 插件
- 迭代器 java_面试必备(含答案):30 个 Java 高频面试问题
- qemu-kvm磁盘读写的缓冲(cache)的五种模式
- java远程执行jmi,java调用matlab 时出现java.lang.NullPointerException错误
- JavaScript学习(八十七)—流程控制语句的总结,超级详细!!!
- tomcat ajp协议安全限制绕过漏洞_Apache tomcat 文件包含漏洞复现(CVE20201938)
- 利用协程实现计时效果
- Python 基础学习Chapter6
- 软件设计师-2.程序设计语言
- 使用LSTM神经网络+CTC loss识别freetype库生成的不定长验证码
- 逆函数求导公式_反函数求导公式
- android简单视频播放器,推荐用于Android超简单视频播放器的ArtPlayer
- MQTT-Eclipse paho mqtt重连机制
- 大二web期末大作业——动漫海贼王(可以很好的应付老师的作业)
- WPF软件导致Win10系统的平板电脑小键盘自动隐藏问题
- JS–for循环嵌套