关于线程锁的认识

一、关于线程锁的认识

  • 1、python多线程针对IO密集型的操作,遇到IO操作就会切换线程。
  • 2、对于多线程同时操作一个数据的时候,我们为了数据的准确性,需要给每个执行动作加上一个线程锁(大白话理解:我们上公共厕所的时候,都会关门上锁,当你出来的时候,别人才可以进去,线程锁也是这个概念,必须等一个线程执行完后才能切换下一个线程)
  • 3、在现实生活中我们常见场景:同一银行账户下,有人存钱,有人取钱,不加锁的时候就会造成,没钱也可以取钱出来

二、同步锁锁对同一个数据进行操作

  • 1、实现代码

      import threading
    
      total = 0
    
      def add():
          global total
          for i in range(1000000):
              total += 1
    
      def reduce():
          global total
          for i in range(1000000):
              total -= 1
    
      if __name__ == "__main__":
          thread1 = threading.Thread(target=add)
          thread2 = threading.Thread(target=reduce)
          thread1.start()
          thread2.start()
          thread1.join()
          thread2.join()
          print('计算结果:', total)
    
  • 2、上面代码每次运行的结果都不一样,主要是两个线程之间不停的抢占资源(切换线程造成的)

  • 3、使用线程锁,把需要锁住的部分锁住

      import threading
    
      total = 0
      # 创建一把锁
      gLock = threading.Lock()
    
      def add():
          global total
          gLock.acquire()
          for i in range(1000000):
              total += 1
          gLock.release()
    
      def reduce():
          global total
          gLock.acquire()
          for i in range(1000000):
              total -= 1
          gLock.release()
    
      if __name__ == "__main__":
          thread1 = threading.Thread(target=add)
          thread2 = threading.Thread(target=reduce)
          thread1.start()
          thread2.start()
          thread1.join()
          thread2.join()
          print('计算结果:', total)
    

二、python中的死锁

是指两个以上的线程同时执行的时候,因相互争夺资源造成一种互相等待的现象,谁也不先释放自己的锁,如果没有外力的情况下,就一直僵持下去,造成死锁的现象,称为死锁。

也许对上面的定义不太理解,举个生活中的例子:小明手上有个苹果,小红手上有香蕉,他们都想交换对方手上的水果,但是两个人没一个人愿意主动或者说是不放心对方(不肯交换),如果没有别人的介入,他们两只能干等对方先主动提出来,这就是死锁的现象

  • 1、产生死锁的代码

      import threading
      import time
    
      class MyThread(threading.Thread):
          def func1(self):
              lockA.acquire()
              print(self.name, '锁A', time.ctime())
    
              lockB.acquire()
              print(self.name, '锁B', time.ctime())
              lockB.release()
    
              lockA.release()
    
          def func2(self):
              lockB.acquire()
              print(self.name, '锁B', time.ctime())
              time.sleep(3)
    
              lockA.acquire()
              print(self.name, '锁A', time.ctime())
              lockA.release()
    
              lockB.release()
    
          def run(self):
              self.func1()
              self.func2()
    
      # 创建一把锁A
      lockA = threading.Lock()
      # 创建一把锁B
      lockB = threading.Lock()
    
      if __name__ == "__main__":
          for i in range(5):
              t = MyThread()
              t.start()
    
  • 2、输出结果

      Thread-1 锁A Sun Jun 10 08:15:13 2018
      Thread-1 锁B Sun Jun 10 08:15:16 2018
      Thread-1 锁B Sun Jun 10 08:15:16 2018
      Thread-2 锁A Sun Jun 10 08:15:16 2018
      ...
      下面就卡死在这里
    
  • 3、上面代码的分析

    • 启动5个线程,当执行run方法的时候线程Thread-1首先抢到A锁,线程Thread-1继续执行,拿到B锁,但是A锁还是没释放出来,直到方法func1全部执行完成,A、B锁才会全部释放出来。
    • 当方法func1执行完后才会进行方法func2,func2先获取B锁,获取到了B锁后注意:B锁还没释放先休眠了3s.
    • func2进入休眠状态,pytyhon不会让程序休息的,会去切换到别的线程上(进行第二个线程),进入线程Thread-2中执行方法func1,获取了锁A,
    • 这个时候线程二要继续获取B锁,可是B锁在线程一种还没被释放出来,线程一休眠3秒后,要获取锁A,可是锁A已经被线程二占用还没释放出来。
    • 上面低四点中,因为两把锁都在对方手上,没被释放出来,都在等待对方先释放,就会卡死在这里。这就是所谓的死锁

三、python中递归锁

为了支持在同一线程中多次请求同一资源,造成死锁的现象,python提供了"可重入锁":threading.RLockRLock内部维护着一个Lock和一个counter(计数器)变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release(counter=0的时候),其他的线程才能获得资源。

  • 1、实现代码

      import threading
      import time
    
      class MyThread(threading.Thread):
              def func1(self):
                      lock.acquire()
                      print(self.name, '锁A', time.ctime())
    
                      lock.acquire()
                      print(self.name, '锁B', time.ctime())
                      lock.release()
    
                      lock.release()
    
              def func2(self):
                      lock.acquire()
                      print(self.name, '锁B', time.ctime())
                      time.sleep(3)
    
                      lock.acquire()
                      print(self.name, '锁A', time.ctime())
                      lock.release()
    
                      lock.release()
    
              def run(self):
                      self.func1()
                      self.func2()
    
      # 创建一把递归锁
      lock = threading.RLock()
    
      if __name__ == "__main__":
              for i in range(5):
                      t = MyThread()
                      t.start()
    
  • 2、代码解答

python中的RLock里面维护了一个计数器,当acquire的时候就+1,当release的时候就-1,如果计数器不为0的时候,别的线程就不糊执行。注意点:必须创建的是同一把锁,不能创建两把递归锁来锁

results matching ""

    No results matching ""