线程同步

共享数据:

  • 如果多个线程共同对某个数据修改,可能出现不可预料的结果,为了保证数据的安全性,需要对多个线程进行同步,一个一个的完成,一个做完另一个才能进来。
  • 效率会降低。

多线程的优势在于可以同时运行多个任务,但是当线程需要共享数据时,可能存在数据不同步的问题。

为了避免这个问题,引入了的概念。

python对线程加锁主要有LockRlock模块

使用Tread对象LockRlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。


Lock模块

用例

import threading
from time import sleep

lock = threading.Lock()

list1 = [0] * 10

def task1():
    # 获取线程锁,如果已经上锁,则等待锁的释放。
    lock.acquire()  # 阻塞
    for i in range(len(list1)):
        list1[i] = 1
        sleep(0.5)
    lock.release()

def task2():
    # 获取线程锁,如果已经上锁,则等待锁的释放。
    lock.acquire()  # 阻塞
    for i in range(len(list1)):
        print("----->",list1[i])
        sleep(0.5)
    lock.release()

if __name__ == '__main__':
    t1 = threading.Thread(target=task1)
    t2 = threading.Thread(target=task2)

    t2.start()
    t1.start()

    t2.join()
    t1.join()

    print(list1)

输出:

-----> 0
-----> 0
-----> 0
-----> 0
-----> 0
-----> 0
-----> 0
-----> 0
-----> 0
-----> 0
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

Lock有acquire()和release()方法,这两个方法必须是成对出现的,acquire()后面必须release()后才能再acquire(),否则会造成死锁


死锁

开发过程中使用线程,在线程间共享多个资源的时候,如果两个线程占有一部分资源并且同时等待对方的资源,就会造成死锁
尽管死锁很少发生,但是一旦放生就会造成应用停止响应,程序不做任何事情。

避免死锁

  • 重构代码
  • 使用timeout参数
from threading import Thread,Lock
from time import sleep

lockA = Lock()
lockB = Lock()

class Mythread1(Thread):
    def run(self) -> None: # 执行start()方法自动寻找run()方法
        if lockA.acquire(): # 如果可以获取到锁,返回True
            print(self.name+'获取到A锁!')
            sleep(0.1)
            if lockB.acquire(timeout=1):    # 阻塞,现在等待不到B锁,设定时间自动释放锁
                print(self.name+'又获取到了B锁!原来还有A锁!')
                lockB.release()
            lockA.release()

class Mythread2(Thread):
    def run(self) -> None: # 执行start()方法自动寻找run()方法
        if lockB.acquire(): # 如果可以获取到锁,返回True
            print(self.name+'获取到B锁!')
            sleep(0.1)
            if lockA.acquire():
                print(self.name+'又获取到了A锁!原来还有B锁!')
                lockA.release()
            lockB.release()

if __name__ == '__main__':
    t1 = Mythread1()
    t2 = Mythread2()

    t1.start()
    t2.start()

    t1.join()
    t2.join()
    print('结束!!!!!!!!!!!!!')

输出:

Thread-1获取到A锁!
Thread-2获取到B锁!
# 此处Thread-1等待B锁因为timeout=1等待1秒后,自动释放了
Thread-2又获取到了A锁!原来还有B锁!
结束!!!!!!!!!!!!!