有如下python代码:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
from threading import Lock
import time
import threading

mutex = Lock()


def test_lock(tid):
    global mutex

    try:
        if mutex.acquire(False) is False:
            print 'acquire False' + tid
            return
        else:
            print 'acquire True' + tid
            time.sleep(1)
    except Exception as e:
        print 'ex' + tid
    finally:
        if mutex.locked():
            mutex.release()
            print 'release lock' + tid


if __name__ == '__main__':
    threading.Thread(target=test_lock, args=('1',)).start()
    threading.Thread(target=test_lock, args=('2',)).start()
    threading.Thread(target=test_lock, args=('3',)).start()
    print 'ok'

输出:

acquire True1
acquire False2
release lock2
ok
acquire True3
release lock3

或者

acquire True1
acquire False2
release lock2
ok
acquire True3
release lock1

问题分析:

从输出可以看出,线程1获取了锁,线程2没有获取到锁,返回之前执行finally代码块释放了线程1的锁(所以没有线程1释放锁的输出);而由于线程2将线程1的锁释放了,使得线程3得以拿到锁执行,最后由线程1或者线程3释放锁(谁先执行finally代码块,谁释放)。

本来希望整个test_lock方法同时只能由一个线程进入,但是现在却同时由两个线程执行了,导致业务异常。

分析原因有两点:1;return之前执行了finally代码块;2,Lock的release方法没有限定解锁的线程必须是持有锁的线程,也就是一个线程可以解另一个线程的锁,而在Java中对于可重入锁ReentrantLock这种情况会抛出异常,同时也可使用isHeldByCurrentThread判断是否是当前线程持有锁。

解决方式:

在try之前获取锁,这样就不会由于错误释放锁了