python3 线程与线程之间数据是共享的(锁和死锁)

线程与线程之间数据是共享的

from threading import Thread


def func(lst, name):
    lst.append(66)
    print(name, lst)


if __name__ == '__main__':
    lst = [1, 2]
    t1 = Thread(target=func, args=(lst, "线程1"))
    t2 = Thread(target=func, args=(lst, "线程2"))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print("主线程结束", lst)

执行结果:

线程1 [1, 2, 66]
线程2 [1, 2, 66, 66]
主线程结束 [1, 2, 66, 66]

带有global的线程与线程之间的数据共享情况

from threading import Thread


def func(name):
    global n
    print(f"{name}开始,n={n}")
    n = 0
    print(f"{name}结束,n={n}")


if __name__ == '__main__':
    n = 100
    t1 = Thread(target=func, args=("线程1",))
    t1.start()
    t1.join()
    print(f"主线程结束,n={n}")

执行结果:

线程1开始,n=100
线程1结束,n=0
主线程结束,n=0

接下来看一个由于线程之间的数据是共享而引发问题

from threading import Thread


def func(name):
    print(f"{name}开始")
    global n
    for i in range(100000):
        n += 1
    print(f"{name}结束,n={n}")


if __name__ == '__main__':
    n = 0
    t1 = Thread(target=func, args=("线程1",))
    t2 = Thread(target=func, args=("线程2",))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f"主线程结束,n={n}")

执行结果:

线程1开始
线程2开始
线程1结束,n=165337
线程2结束,n=147914
主线程结束,n=147914

最终的结果不是我们预期的200000

解决线程与线程之间数据共享导致的问题:加锁

from threading import Thread, Lock


def func(name, lock: Lock):  # 传递lock,后面添加: Lock表示是Lock类型的是为了上锁和释放锁的时候会有方法提示功能
    print(f"{name}开始")
    global n
    for i in range(100000):
        lock.acquire()  # 上锁
        n += 1
        lock.release()  # 释放锁
    print(f"{name}结束,n={n}")


if __name__ == '__main__':
    lock = Lock()  # 创建一把锁
    n = 0
    t1 = Thread(target=func, args=("线程1", lock))
    t2 = Thread(target=func, args=("线程2", lock))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f"主线程结束,n={n}")

执行结果:

线程1开始
线程2开始
线程1结束,n=167229
线程2结束,n=200000
主线程结束,n=200000

只看最终结果就行,因为线程1和线程2是并行执行的。

线程与线程之间数据共享(加锁)

from threading import Thread, Lock


n = 0
def func(lock, name):
    lock.acquire()
    global n
    for i in range(1000000):
        n += 1
    print("%s拿到了锁" % name)
    lock.release()


if __name__ == '__main__':
    lock = Lock()  # 线程锁
    t1 = Thread(target=func, args=(lock, "线程1"))
    t2 = Thread(target=func, args=(lock, "线程2"))
    t3 = Thread(target=func, args=(lock, "线程3"))
    t1.start()
    t2.start()
    t3.start()
    t1.join()
    t2.join()
    t3.join()
    print(n)

运行结果:

线程1拿到了锁
线程2拿到了锁
线程3拿到了锁
3000000

死锁现象

from threading import Thread, Lock


def func(name, lock: Lock):  # 传递lock,后面添加: Lock表示是Lock类型的,是为了上锁和释放锁的时候会有方法提示功能
    print(f"{name}开始")
    lock.acquire()  # 上锁
    lock.acquire()  # 上锁
    print(f"{name}被锁住了")
    lock.release()  # 释放锁
    lock.release()  # 释放锁
    print(f"{name}结束")


if __name__ == '__main__':
    lock = Lock()  # 创建一把锁
    t1 = Thread(target=func, args=("线程1", lock))
    t2 = Thread(target=func, args=("线程2", lock))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f"主线程结束")

执行结果:

线程1开始
线程2开始

程序一直执行不完,因为程序被锁住了。

解决死锁--->使用递归锁RLock

from threading import Thread, RLock


def func(name, lock: RLock):  # 传递lock,后面添加: Lock表示是Lock类型的,是为了上锁和释放锁的时候会有方法提示功能
    print(f"{name}开始")
    lock.acquire()  # 上锁
    lock.acquire()  # 上锁
    print(f"{name}被锁住了")
    lock.release()  # 释放锁
    lock.release()  # 释放锁
    print(f"{name}结束")


if __name__ == '__main__':
    lock = RLock()  # 创建一把锁
    t1 = Thread(target=func, args=("线程1", lock))
    t2 = Thread(target=func, args=("线程2", lock))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f"主线程结束")

执行结果:

线程1开始
线程1被锁住了
线程1结束
线程2开始
线程2被锁住了
线程2结束
主线程结束

完美解决死锁的问题,切记锁可以保证数据的安全性,但是效率会降低,相当于把并行改为了串行。

死锁可以想成两个人围着桌子吃饭,两个人的中间各放着一根的筷子,两根筷子在一起才能吃饭,此时,两个人都想吃饭,但是都抓着筷子不放开,结果谁也吃不上饭,就僵死在那了。

原文地址:https://www.cnblogs.com/lilyxiaoyy/p/12055146.html