方法一:while循环法
这个解法用于理解多线程的阻塞,相当于先用某些方法卡住执行顺序,然后不断监控目标,直到目标符合条件时才跳出当前断点继续执行后续语句。
class Foo:
def __init__(self):
self.t = 0
def first(self, printFirst: 'Callable[[], None]') -> None:
printFirst()
self.t = 1
def second(self, printSecond: 'Callable[[], None]') -> None:
while self.t != 1:
pass
printSecond()
self.t = 2
def third(self, printThird: 'Callable[[], None]') -> None:
while self.t != 2:
pass
printThird()
while会跑满CPU影响GIL上下文切换的判定,可以加入time.sleep,将CPU交还给GIL,及时切换线程。
方法二:time.sleep睡眠法
from time import sleep
class Foo:
def __init__(self):
self.t = 0
def first(self, printFirst: 'Callable[[], None]') -> None:
printFirst()
self.t = 1
def second(self, printSecond: 'Callable[[], None]') -> None:
while self.t != 1:
sleep(1e-3)
printSecond()
self.t = 2
def third(self, printThird: 'Callable[[], None]') -> None:
while self.t != 2:
sleep(1e-3)
printThird()
方法三:with Condition条件对象法
调用了threading模块里的Condition方法,启动wait_for阻塞每个函数,达到各个函数对应的目标值才释放线程;with用来替代try语句,with是配合Condition方法常用的语法糖。
import threading
class Foo:
def __init__(self):
self.c = threading.Condition()
self.t = 0
def first(self, printFirst: 'Callable[[], None]') -> None:
self.res(0, printFirst)
def second(self, printSecond: 'Callable[[], None]') -> None:
self.res(1, printSecond)
def third(self, printThird: 'Callable[[], None]') -> None:
self.res(2, printThird)
def res(self, val: int, func: 'Callable[[], None]') -> None:
with self.c:
self.c.wait_for(lambda: val == self.t) # 参数是函数对象,返回值是bool类型
func()
self.t += 1
self.c.notify_all()
方法四:Lock锁对象法
初始化时添加acquire进行阻塞,调用其他函数的时候按顺序release释放。
import threading
class Foo:
def __init__(self):
self.l1 = threading.Lock()
self.l1.acquire()
self.l2 = threading.Lock()
self.l2.acquire()
def first(self, printFirst: 'Callable[[], None]') -> None:
printFirst()
self.l1.release()
def second(self, printSecond: 'Callable[[], None]') -> None:
self.l1.acquire()
printSecond()
self.l2.release()
def third(self, printThird: 'Callable[[], None]') -> None:
self.l2.acquire()
printThird()
方法五:Semaphore信号量对象法
和Lock方法类似,不过在类赋值的时候可以带有参数自带阻塞。
import threading
class Foo:
def __init__(self):
self.s1 = threading.Semaphore(0)
self.s2 = threading.Semaphore(0)
def first(self, printFirst: 'Callable[[], None]') -> None:
printFirst()
self.s1.release()
def second(self, printSecond: 'Callable[[], None]') -> None:
self.s1.acquire()
printSecond()
self.s2.release()
def third(self, printThird: 'Callable[[], None]') -> None:
self.s2.acquire()
printThird()
方法六:Event事件对象法
原理也是添加阻塞,然后释放线程,和Lock和Semaphore一样,不过event用wait方法作为阻塞,用set来释放线程,默认类赋值就是阻塞的。
import threading
class Foo:
def __init__(self):
self.e1 = threading.Event()
self.e2 = threading.Event()
def first(self, printFirst: 'Callable[[], None]') -> None:
printFirst()
self.e1.set()
def second(self, printSecond: 'Callable[[], None]') -> None:
self.e1.wait()
printSecond()
self.e2.set()
def third(self, printThird: 'Callable[[], None]') -> None:
self.e2.wait()
printThird()
方法七:Barrier栅栏对象法
Barrier初始化的时候定义了parties = 2个等待线程,调用完了parties个wait就会释放线程。
import threading
class Foo:
def __init__(self):
self.b1 = threading.Barrier(2)
self.b2 = threading.Barrier(2)
def first(self, printFirst: 'Callable[[], None]') -> None:
printFirst()
self.b1.wait()
def second(self, printSecond: 'Callable[[], None]') -> None:
self.b1.wait()
printSecond()
self.b2.wait()
def third(self, printThird: 'Callable[[], None]') -> None:
self.b2.wait()
printThird()
方法八:Queue队列法
当队列为空时,get方法就会自动阻塞,直到put使之非空才会释放进程。
import queue
class Foo:
def __init__(self):
self.q1 = queue.Queue()
self.q2 = queue.Queue()
def first(self, printFirst: 'Callable[[], None]') -> None:
printFirst()
self.q1.put(0)
def second(self, printSecond: 'Callable[[], None]') -> None:
self.q1.get() # Remove and return an item from the queue.
printSecond()
self.q2.put(0) # Put an item into the queue
def third(self, printThird: 'Callable[[], None]') -> None:
self.q2.get()
printThird()
方法九:定长队列法
对于定长队列来说,如果队列已满,那么put方法也是阻塞。
import queue
class Foo:
def __init__(self):
self.q1 = queue.Queue(1)
self.q1.put(0)
self.q2 = queue.Queue(1)
self.q2.put(0)
def first(self, printFirst: 'Callable[[], None]') -> None:
printFirst()
self.q1.get()
def second(self, printSecond: 'Callable[[], None]') -> None:
self.q1.put(0)
printSecond()
self.q2.get()
def third(self, printThird: 'Callable[[], None]') -> None:
self.q2.put(0)
printThird()
方法十:字典法
初始化一个空字典,根据键存储对应的函数作为字典的值,当字典长度为3时,按序输出字典。由于该方法集中在最后一个线程进行输出,力扣目前不通过。
class Foo:
def __init__(self):
self.d = {}
def first(self, printFirst: 'Callable[[], None]') -> None:
self.d[0] = printFirst
self.res()
def second(self, printSecond: 'Callable[[], None]') -> None:
self.d[1] = printSecond
self.res()
def third(self, printThird: 'Callable[[], None]') -> None:
self.d[2] = printThird
self.res()
def res(self) -> None:
if len(self.d) == 3:
self.d[0]()
self.d[1]()
self.d[2]()