第五步:线程A使用了num值8
因为num只有一个,而三个操作都针对一个num进行,所以上面的操作过程是完全有可能的,而原来线程A、B、C想要使用的num值应该分别为:7、9、8,这里却变成了:8、8、7。试想一下,如果这三个线程的操作对整个程序的执行是至关重要的,会造成什么样的后果?
因此出于程序稳定运行的考虑,对于线程需要调用内存中的共享数据时,我们就需要为线程加锁。 2.Python多线程锁 (1)
先看下面一个未给线程加锁的程序代码:
import threading
import time
number = 0
def run(num):
global number
number += 1
print number
time.sleep(1)
for i in range(20):
t = threading.Thread(target=run, args=(i,))
t.start()
程序执行结果如下:
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day6$ python thread_clock6.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
上面是多个线程同时抢占同一内存空间的例子,但从执行结果中可以看到,程序依然顺序地输出1-19,而没有出现上面说的情况,那是仅仅是因为量少的原因,虽然执行正常,没有出错,但是并不代表不会出错。 (2)
看下面给线程加锁的代码:
import threading
import time
number = 0
lock = threading.RLock() #调用threading模块中的RLock()
def run(num):
lock.acquire() #开始给线程加锁
global number
number += 1
lock.release() #给线程解锁
print number
time.sleep(1)
for i in range(20):
t = threading.Thread(target=run, args=(i,))
t.start()
程序执行结果如下:
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day6$ python thread_clock6.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
程序的执行结果肯定是会正常的,而在没有给线程加锁之前,则有可能是正常,注意这是两种完全不同的概念。
分析一下上面的程序:在某一线程修改num的值时,即给该线程加锁,该线程加锁后,只要是该线程需要调用的代码以及涉及的内存空间,都会立即被锁上,比如这里的"number+=1",其它线程虽然也在并发同时执行,但是不能执行"number+=1"这行代码的,即不能够去访问或修改num这一个共享内存空间的数据,只能等待该线程解锁后才能执行;当该线程解锁后,另一个线程马上加锁再来修改number的值,同时也不允许其它线程占用,如此类推,直到所有线程执行完毕。
根据上面的分析,为线程加锁就可以解决前面讲的线程安全问题。 (3)
为了更好的理解线程加锁的一个过程,把上面的代码修改为如下:
import threading
import time
number = 0
lock = threading.RLock()
def run(num):
lock.acquire()
global number
number += 1
print number
time.sleep(1) #把time.sleep(1)也锁在线程中
lock.release()
for i in range(20):
t = threading.Thread(target=run, args=(i,))
t.start()
执行结果如下:
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day6$ python thread_clock6.py
1