1 守护线程
守护线程(Daemon thread)
,又叫做后台线程。此类线程的特点是当其他线程都执行结束时,无论守护线程是否完成,都直接结束当前工作。例如,python中的垃圾回收机制就是守护线程的代表,当主线程和其他线程完成工作后,垃圾回收机制也就没有再继续执行的必要了。
创建守护线程可以在创建线程时,将daemon
属性值设置为True
,下面的例子展示了如何创建守护线程。
# coding:utf-8
import threading
def action(length):
for i in range(length):
print(threading.current_thread())
if __name__ == "__main__":
t = threading.Thread(target=action, args=(20,), daemon=True)
# t.daemon = True # 此中方法也可以开启守护线程
t.start()
for i in range(5):
print(threading.current_thread())
输出结果:
<Thread(Thread-1, started daemon 123145454514176)>
<Thread(Thread-1, started daemon 123145454514176)>
<Thread(Thread-1, started daemon 123145454514176)>
<Thread(Thread-1, started daemon 123145454514176)>
<Thread(Thread-1, started daemon 123145454514176)>
<Thread(Thread-1, started daemon 123145454514176)>
<Thread(Thread-1, started daemon 123145454514176)>
<Thread(Thread-1, started daemon 123145454514176)>
<Thread(Thread-1, started daemon 123145454514176)>
<_MainThread(MainThread, started 4672699840)><Thread(Thread-1, started daemon 123145454514176)>
<_MainThread(MainThread, started 4672699840)>
<_MainThread(MainThread, started 4672699840)>
<_MainThread(MainThread, started 4672699840)>
<_MainThread(MainThread, started 4672699840)>
2 互斥锁
互斥锁用于解决线程之间数据不同步的问题,例如给出下面一段代码,用于模仿银行用户取钱的操作:
# coding:utf-8
import threading
import time
class Account(object):
"""
定义账户的类
"""
def __init__(self, account_no, balance):
"""
:param account_no: 唯一的账户号
:param balance: 账户对应的余额
"""
self.account_no = account_no
self.balance = balance
def withdraw(account, draw_amount):
"""
取钱操作
:param account: 账户类的实例化对象
:param draw_amount: 取钱金额
:return: None
"""
if account.balance >= draw_amount:
print(threading.current_thread().getName() + " Withdraw success ", draw_amount)
time.sleep(0.5) # sleep函数会使当前线程阻塞,从而切换到另一线程
account.balance -= draw_amount
print("balance is ", account.balance)
else:
print("Withdraw failure")
if __name__ == "__main__":
# 创建一个账户,两个用户分别取钱,会出现数据不同步引发的错误
acc = Account("62102034", 1000) # 创建账户,包含两个属性,账户号和余额
th1 = threading.Thread(target=withdraw, args=(acc, 800))
th2 = threading.Thread(target=withdraw, args=(acc, 800))
th1.start()
th2.start()
输出结果:
Thread-1 Withdraw success 800
Thread-2 Withdraw success 800
balance is 200
balance is -600
此时会出现一个问题,当第一个线程执行余额和取钱数目判断操作时,系统判定可以成功取钱,但是紧接着执行了一个sleep
的函数使得当前线程进入阻塞状态,第二个线程重复上述操作,最后造成了两个线程同时可以成功取钱。threading
模块引入RLock
类可以锁定当前进程,从而可以实现在一个线程上实现独享数据。
lock = threading.RLock()类构建一个互斥锁的对象,用于锁定当前进程的数据
lock.acquire() 对lock对象加锁
lock.release() 对lock对象释放锁
acquire和release方法必须成对出现
RLock
对象的acquire
和release
方法必须成对出现,同时将两个方法应用到线程执行的函数体中,就可以实现对线程加锁。
# coding:utf-8
import threading
import time
class Account(object):
# 定义账户的类
def __init__(self, account_no, balance):
"""定义构造器"""
self.account_no = account_no
self._balance = balance # 为了账户安全,定义余额为类的内部属性,
self.lock = threading.RLock() # 定义lock属性为互斥锁对象
def withdraw(self, withdraw_amount):
"""
取钱操作
:param withdraw_amount: 取钱金额
:return: None
"""
self.lock.acquire() # 线程加锁
if self._balance >= withdraw_amount:
print(threading.current_thread().getName(), " Withdraw success ", withdraw_amount)
time.sleep(0.5)
self._balance -= withdraw_amount # 更新余额
print("balance is ", self._balance)
else:
print(threading.current_thread().getName(), "Withdraw failure")
self.lock.release() # 线程释放锁
if __name__ == "__main__":
acc = Account("62102034", 1000)
th1 = threading.Thread(target=acc.withdraw, args=(800,))
th2 = threading.Thread(target=acc.withdraw, args=(800,))
th1.start()
th2.start()
输出结果:
Thread-1 Withdraw success 800
balance is 200
Thread-2 Withdraw failure
另外,也可以使用上一小节提到的join
方法应用到某一个线程,使其优先占用CPU资源完成当前线程工作。
# coding:utf-8
import threading
import time
class Account(object):
# 定义账户的类
def __init__(self, account_no, balance):
"""定义构造器"""
self.account_no = account_no
self._balance = balance # 为了账户安全,定义余额为类的内部属性,
self.lock = threading.RLock() # 定义lock属性为互斥锁对象
def withdraw(self, withdraw_amount):
"""
取钱操作
:param withdraw_amount: 取钱金额
:return: None
"""
# self.lock.acquire() # 线程加锁
if self._balance >= withdraw_amount:
print(threading.current_thread().getName(), " Withdraw success ", withdraw_amount)
time.sleep(0.5)
self._balance -= withdraw_amount # 更新余额
print("balance is ", self._balance)
else:
print(threading.current_thread().getName(), "Withdraw failure")
# self.lock.release() # 线程释放锁
if __name__ == "__main__":
acc = Account("62102034", 1000)
th1 = threading.Thread(target=acc.withdraw, args=(800,))
th2 = threading.Thread(target=acc.withdraw, args=(800,))
th1.start()
th1.join()
th2.start()
输出结果:
Thread-1 Withdraw success 800
balance is 200
Thread-2 Withdraw failure
网友评论