1. 线程间的资源竞争
- 一个线程写入,另一个线程读取,是可以的,如果两个线程都要写入,就需要想办法了
- 创建一把锁,默认是没有上锁,是不可能重复的锁,只能创建一次
- mutex = threading.Lock()
2. 互斥锁和死锁
2.1 互斥锁
- 当多个线程同时共享数据的时候,需要同步控制
- 某个线程要先修改共享数据时,要先将其锁定,此时资源的状态为锁定,其他线程不能改变,变成‘非锁定’的时候,其他线程才能再一次锁定资源。互斥锁保证了每次只有一个线程读取和写入,保证了多线程状态下数据的准确性
# 1.创建锁
mutex = threading.Lock()
# 2.锁定
mutex.acquire()
# 3.解锁
mutex.release
2.2 死锁
线程之间共享多个资源的时候,如果两个线程同时占用一部分资源,又互相等待对方的时候,就造成了死锁
import threading
import time
class MyThread1(threading.Thread):
def run(self):
# 对mutex A上锁
mutexA.acquire()
# 对mutex A上锁后,延时1s,等待另一个线程,把B上锁
print(self.name+'------do1-----up----')
time.sleep(1)
mutexB.acquire()
print(self.name+'-----do1-----down-----')
mutexB.release()
mutexA.release()
class MyThread2(threading.Thread):
def run(self):
# 对mutex A上锁
mutexB.acquire()
# 对mutex A上锁后,延时1s,等待另一个线程,把B上锁
print(self.name+'------do1-----up----')
time.sleep(1)
mutexA.acquire()
print(self.name+'-----do1-----down-----')
mutexA.release()
mutexB.release()
mutexA = threading.Lock()
mutexB = threading.Lock()
if __name__ == '__main__':
t1 = MyThread1()
t2 = MyThread2()
t1.start()
t2.start()
2.3 避免死锁
- 程序设计时要尽量避免,添加超时时间等等
3. Queue线程
- 访问全局变量,需要经常加锁,把数据存放到队列中,可以用python提供的安全模块queue
- python中的安全模块queue提供了安全的同步的队列类,包括FIFO(先进先出)队列queue,LIFO(后入先出)队列LifoQueue,这些队列实现了锁原语,能够在线程中直接所用,使队列实现线程间同步
1. 初始化Queue(maxsize):创建一个先入先出队列。
2. empty():判断队列是否为空
3. full():判断队列是否满了
4. get():从队列中取出最后一个数据
5. put():将一个数据放入队列中
4. 线程同步
天猫精灵:小爱同学
小爱同学:在
天猫精灵:现在几点了?
小爱同学:你猜猜现在几点了
5. 生产者和消费者
- 生产者和消费者是多线程开发中的一种模式,通过这种模式,可以让代码达到高内聚低耦合的目标,线程管理更加方便,程序分工更加明确
- 生产者的线程用来生产数据,消费者再容器中取出数据进行消费
5.1 Lock版生产者和消费者
import threading
import random
gMoney = 0
gTimes = 0
gLock = threading.Lock()
class Producer(threading.Thread):
def run(self):
global gMoney
global gTimes
gLock.acquire()
while True:
if gTimes >= 10:
break
money = random.randint(0, 100)
gMoney += money
gTimes += 1
print("%s生产了%d元钱" % (threading.current_thread().name, money))
gLock.release()
class Customer(threading.Thread):
def run(self):
global gMoney
while True:
gLock.acquire()
money = random.randint(0, 100)
if gMoney >= money:
gMoney -= money
print("%s消费了%d元钱" % (threading.current_thread().name, money))
else:
if gTimes >= 10:
gLock.release()
break
print("%s想消费%d元钱,但是余额只有%d" % (threading.current_thread().name, money, gMoney))
gLock.release()
def main():
for x in range(5):
th = Producer(name = "生产者%d号" % x)
th.start()
for x in range(5):
th = Customer(name = "消费者%d" % x)
th.start()
if __name__ == '__main__':
main()
5.2 Condition版生产者和消费者
import threading
import random
gMoney = 0
gTimes = 0
gCon = threading.Condition()
class Producer(threading.Thread):
def run(self):
global gMoney
global gTimes
while True:
gCon.acquire()
if gTimes >= 10;
gCon.release()
break
money = random.randint(0, 100)
gMoney += money
gTimes += 1
print("%s生产了%d元钱,剩余了%d元钱" % (threading.current_thread().name, money,gMoney))
gCon.notify_all()
gCon.release()
class Customer(threading.Thread):
def run(self):
global gMoney
while True:
gCon.acquire()
money = random.randint(0, 100)
while gMoney < money:
if gTime >= 10:
gCon.release()
return
print("%s想消费%d元钱,但是余额只有%d元钱" % (threading.current_thread().name, money, gMoney))
gCon.wait()
gMoney -= money
print("%s消费了%d元钱,剩下%d元钱" % (threading.current_thread().name, money, gMoney))
gCon.release()
def main():
for x in range(5):
th = Producer(name = "生产者%d号" % x)
th.start()
for x in range(5):
th = Customer(name = "消费者%d号" % x)
th.start()
if __name__ == '__main__':
main()