线程安全
- 无问题时
1 import threading 2 3 m = 0 4 # 如果多个线程去操作同一个外部资源,那么就可能造成线程的不安全。 5 # 多个线程同时访问同一个外部资源,就可能会出现读写冲突 6 def increase(): 7 global m 8 for i in range(100): # 循环次数少,不会出现问题 9 m += 1 10 print(m) 11 12 # 线程冲突 13 def conflict(): 14 # 创建5个线程,这5个线程同时的去操作外部的m变量 15 for _ in range(5): 16 t = threading.Thread(target=increase) 17 t.start() 18 # 现在是5个线程同时在访问m,当所有的线程都开启以后,操作系统会将他们放入一个轮询队列中去并发执行(每个线程分配一个时间片)。 19 # 当循环次数较少(执行这个线程用的时间越少),使用的时间不足以超出时间片,如果时间过长(即耗时任务)就会超出时间片,就会进而让出cpu 20 21 22 if __name__ == '__main__': 23 conflict()
1 运行结果: 2 """ 3 100 4 200 5 300 6 400 7 500 8 """
- 出现线程冲突
1 import threading 2 3 m = 0 4 # 如果多个线程去操作同一个外部资源,完成这个任务所花的时间远远超出线程的时间片。此线程还没有完成对此外部资源的操作,其他资源就来操作了,那么就可能造成线程的不安全。 5 # 多个线程同时访问同一个外部资源,就可能会会出现读写冲突 6 def increase(): 7 global m 8 for i in range(1000000): # 循环次数多,出现问题 9 m += 1 10 print(m) 11 12 # 线程冲突 13 def conflict(): 14 # 创建5个线程,这5个线程同时的去操作外部的m变量 15 for _ in range(5): 16 t = threading.Thread(target=increase) 17 t.start() 18 # 现在是5个线程同时在访问m,当所有的线程都开启以后,操作系统会将他们放入一个轮询队列中去并发执行(每个线程分配一个时间片)。 19 # 当循环次数较少(执行这个线程用的时间越少),使用的时间不足以超出时间片,如果时间过长(即耗时任务)就会超出时间片,就会进而让出cpu 20 21 22 if __name__ == '__main__': 23 conflict()
1 运行结果: 2 """ 3 1554797 4 1765071 5 1850168 6 1916170 7 2079668 8 """ 9 10 # ------------------- 运行结果出现错误-----------------------
解决办法
-
使用线程同步
1 import threading 2 3 m = 0 4 # 如果多个线程去操作同一个外部资源,那么就可能造成线程的不安全。 5 # 多个线程同时访问同一个外部资源,就可能会会出现读写冲突 6 def increase(): 7 global m 8 for i in range(1000000): # 循环次数少,不会出现问题 9 m += 1 10 print(m) 11 # 加入线程同步来解决线程冲突 12 def threadSync(): 13 for _ in range(5): 14 t = threading.Thread(target=increase) 15 t.start() 16 # 将线程加入同步对列。。但线程同步会造成线程的阻塞 17 t.join() # 同步就是串行,将所有的任务加入到同一个同步队列中,前面的任务不执行完后面的不能开启 18 19 if __name__ == '__main__': 20 21 threadSync()
- 给资源加互斥锁 [只有读或只有写操作加互斥锁]
1 import threading 2 3 m = 0 4 lock = threading.Lock() # 创建一个互斥锁,不会造成线程阻塞问题 5 def increase2(): 6 global m 7 if lock.acquire(): # 获取互斥锁,并作出判断 8 for i in range(1000000): 9 m += 1 10 print(m) 11 lock.release() # 使用完毕以后解除互斥锁 12 print("我是线程:",threading.current_thread().name) 13 14 def threadLock(): 15 for _ in range(5): 16 t = threading.Thread(target=increase2) 17 t.start() 18 19 if __name__ == '__main__': 20 threadLock() 21 22 # -------------- 正常输出结果 ---------------