使用 threading 模块中 Thread 类的构造器创建线程。即直接对类 threading.Thread 进行实例化创建线程,并调用实例化对象的 start() 方法启动线程。
代码演示:
import threading
#定义线程要调用的方法,*add可接收多个以非关键字方式传入的参数
def action(*add):
for arc in add:
#调用 getName() 方法获取当前执行该程序的线程名
print(threading.current_thread().getName() +" "+ arc)
#定义为线程方法传入的参数
my_tuple = ("python1",\
"python2",\
"python3")
#创建线程
thread = threading.Thread(target = action,args =my_tuple)
#启动线程
thread.start()
执行效果:
Thread-1 python1
Thread-1 python2
Thread-1 python3
代码演示:
import threading
#定义线程要调用的方法,*add可接收多个以非关键字方式传入的参数
def action(*add):
for arc in add:
#调用 getName() 方法获取当前执行该程序的线程名
print(threading.current_thread().getName() +" "+ arc)
#定义为线程方法传入的参数
my_tuple = ("python1",\
"python2",\
"python3")
#创建线程
thread = threading.Thread(target = action,args =my_tuple)
#启动线程
thread.start()
for i in range(5):
print(threading.current_thread().getName())
执行结果:
Thread-1 python1MainThread
MainThread
MainThread
MainThread
Thread-1 python2MainThread
Thread-1 python3
我们可以看到,当有 2 个线程时,分别为主线程 MainThread 和子线程 Thread-1,它们以并发方式执行,即 Thread-1 执行一段时间,然后 MainThread 执行一段时间。通过轮流获得 CPU 执行一段时间的方式,程序的执行在多个线程之间切换,从而给用户一种错觉,即多个线程似乎同时在执行。
继承 threading 模块中的 Thread 类创建线程类。即用 threading.Thread 派生出一个新的子类,将新建类实例化创建线程,并调用其 start() 方法启动线程。
通过继承 Thread 类,我们可以自定义一个线程类,从而实例化该类对象,获得子线程。
需要注意的是,在创建 Thread 类的子类时,必须重写从父类继承得到的 run() 方法。因为该方法即为要创建的子线程执行的方法,其功能如同第一种创建方法中的 action() 自定义函数。
代码演示:
import threading
#创建子线程类,继承自 Thread 类
class my_Thread(threading.Thread):
def __init__(self,add):
threading.Thread.__init__(self)
self.add = add
# 重写run()方法
def run(self):
for arc in self.add:
#调用 getName() 方法获取当前执行该程序的线程名
print(threading.current_thread().getName() +" "+ arc)
#定义为 run() 方法传入的参数
my_tuple = ("python1",\
"python2",\
"python3")
#创建子线程
mythread = my_Thread(my_tuple)
#启动子线程
mythread.start()
#主线程执行此循环
for i in range(5):
print(threading.current_thread().getName())
执行结果:
Thread-1 python1MainThread
MainThread
Thread-1 python2
MainThreadThread-1 python3
MainThread
MainThread
线程从创建到消亡会历经 5 种状态,分别是新建、就绪、运行、阻塞和死亡
新建:新创建的线程在调用 start() 方法之前,不会得到执行,此阶段的线程就处于新建状态。
就绪:当位于新建状态的线程调用 start() 方法后,该线程就转换到就绪状态。
运行:当位于就绪状态的线程得到了 CPU,并开始执行 target 参数执行的目标函数或者 run() 方法,就表明当前线程处于运行状 态。
阻塞:如果当前有多个线程处于就绪状态(等待 CPU 调度)时,处于运行状态的线程将无法一直霸占 CPU 资源,为了使其它线 程也有执行的机会,CPU 会在一定时间内强制当前运行的线程让出 CPU 资源,以供其他线程使用。而对于获得 CPU 调度 却没有执行完毕的线程,就会进入阻塞状态。
死亡:对于获得 CPU 调度却未执行完毕的线程,它会转入阻塞状态,待条件成熟之后继续转入就绪状态,重复争取 CPU 资源, 直到其执行结束。执行结束的线程将处于死亡状态。
Python支持创建另一种线程,称为守护线程(或后台线程)。此类线程的特点是,当程序中主线程及所有非守护线程执行结束时,未执行完毕的守护线程也会随之消亡(进行死亡状态),程序将结束运行。
代码演示:
import threading
#定义线程要调用的方法,*add可接收多个以非关键字方式传入的参数
def action(length):
for arc in range(length):
#调用 getName() 方法获取当前执行该程序的线程名
print(threading.current_thread().getName()+" "+str(arc))
#创建线程
thread = threading.Thread(target = action,args =(20,))
#将thread设置为守护线程
thread.daemon = True
#启动线程
thread.start()
#主线程执行如下语句
for i in range(5):
print(threading.current_thread().getName())
执行结果:
Thread-1 0MainThread
Thread-1 1
Thread-1 2
MainThread
Thread-1 3
Thread-1 4
Thread-1 5
Thread-1 6
Thread-1 7
Thread-1 8
Thread-1 9
MainThread
MainThread
Thread-1 10MainThread
当两个线程相互等待对方释放资源时,就会发生死锁。
一旦出现死锁,整个程序既不会发生任何异常,也不会给出任何提示,只是所有线程都处于阻塞状态,无法继续。
代码演示:
import threading
import time
class A:
def __init__(self):
self.lock = threading.RLock()
def foo(self, b):
try:
self.lock.acquire()
print("当前线程名: " + threading.current_thread().name\
+ " 进入了A实例的foo()方法" )
time.sleep(0.2)
print("当前线程名: " + threading.current_thread().name\
+ " 企图调用B实例的last()方法")
b.last()
finally:
self.lock.release()
def last(self):
try:
self.lock.acquire()
print("进入了A类的last()方法内部")
finally:
self.lock.release()
class B:
def __init__(self):
self.lock = threading.RLock()
def bar(self, a):
try:
self.lock.acquire()
print("当前线程名: " + threading.current_thread().name\
+ " 进入了B实例的bar()方法" )
time.sleep(0.2)
print("当前线程名: " + threading.current_thread().name\
+ " 企图调用A实例的last()方法")
a.last()
finally:
self.lock.release()
def last(self):
try:
self.lock.acquire()
print("进入了B类的last()方法内部")
finally:
self.lock.release()
a = A()
b = B()
def init():
threading.current_thread().name = "主线程"
# 调用a对象的foo()方法
a.foo(b)
print("进入了主线程之后")
def action():
threading.current_thread().name = "副线程"
# 调用b对象的bar()方法
b.bar(a)
print("进入了副线程之后")
# 以action为target启动新线程
threading.Thread(target=action).start()
# 调用init()函数
init()
执行效果:
死锁了
程序既无法向下执行,也不会抛出任何异常,就一直“僵持”着。究其原因,是因为上面程序中 A 对象和 B 对象的方法都是线程安全的方法。
程序中有两个线程执行,副线程的线程执行体是 action() 函数,主线程的线程执行体是 init() 函数(主程序调用了 init() 函数)。其中在 action() 函数中让 B 对象调用 bar() 方法,而在 init() 函数中让 A 对象调用 foo() 方法。
死锁是不应该在程序中出现的,在编写程序时应该尽量避免出现死锁。下面有几种常见的方式用来解决死锁问题:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。