前面一节的案例提出了多线程数据同步所存在的问题,当多个Author线程修改同一个共享数据时,会发生数据覆盖或丢失的问题。
为了解决多个线程修改同一数据而发生数据覆盖或丢失的问题,Python提供了Lock对象来加保护伞,以保证数据的安全。线程调用Lock对象的acquire方法来获取锁对象(如果其他线程已经获得该锁,则当前线程需等待被释放),待资源访问完后,在调用release方法释放锁。
主线程修改代码如下:
import book
import author
import time
import threading
#获得lock对象
lock = threading.Lock()
def main():
b = book.Book("");
w1 = author.Author(b,"join",2,lock)
w1.start()
w2 = author.Author(b, "May",2,lock)
w2.start()
w3 = author.Author(b, "Kenny",1,lock)
w3.start()
w4 = author.Author(b, "Joyce",2,lock)
w4.start()
w5 = author.Author(b, "Alex",2,lock)
w5.start()
time.sleep(10)
print("共同创作的图书内容:%s" % (b.getContent()))
if __name__ == '__main__':
main()上面的代码通过threading模块的lock()方法获取Lock对象,并传入到创建的Author线程里。
Author线程的代码如下:
import threading import time import book # 声明图书类 class Author(threading.Thread): # 作者类构造方法 def __init__(self, inDocBook,inName,inWaitTime,inlock): threading.Thread.__init__(self) self.docbook = inDocBook self.name = inName self.waittime = inWaitTime self.lock = inlock def getDocBook(self): return self.docbook def setDocBook(self, inDocBook): self.docbook = inDocBook def run(self): # 中断线程 self.lock.acquire() content = self.docbook.getContent() + "\n" + self.name + ":我的创作内容" time.sleep(self.waittime) self.docbook.setContent(content) self.lock.release()
在Author线程的run()方法中,使用锁对象对content数据进行保护,被加锁的content数据不能被其它线程修改,直至锁对象被释放后,其它线程才能获取该数据的修改权。
程序经过改造后,输出结果如下图所示:
图 1 使用Lock对象后程序输出结果
从输出结果可以看出,创作的内容都获得了输出,这得益于Lock对象对共享数据的保护作用。Lock对象实际上是一个互斥锁,Lock对象应在主线程创建,并在主线程创建的子线程中使用。当子线程需要修改主线程的共享数据时,子线程调用Lock对象的acquire()方法获取锁对象,对共享数据加锁保护,共享数据被加锁后,其它线程将无法获得共享数据的使用权,直至子线程调用Lock对象的release()方法释放锁。