Leetcode多线程编程:交替打印FooBar Python题解
首先,要想写出本题,首先先要理解一个概念,就是Semaphore对象
Semaphore()
Semaphore对象内部管理着一个计数器,该计数器由每个
acquire()调用递减,并由每个
release()调用递增。计数器永远不会低于0,当
acquire()发现计数器为0的时候,线程阻塞,等待其他线程调用
release()`。
import time
import threading
def test():
time.sleep(2)
print(time.ctime())
for i in range(5):
t1=threading.Thread(target=test,args=()) # 实例化一个线程
t1.start() # 启动线程
执行结果:
Thu Jul 18 14:48:01 2019
Thu Jul 18 14:48:01 2019
Thu Jul 18 14:48:01 2019
Thu Jul 18 14:48:01 2019
Thu Jul 18 14:48:01 2019
可以看到,程序在很短时间内生成了5个线程
如果是在主机执行IO密集型任务的时候再执行这种类型的程序时,主机有很大可能因为消耗资源过多而宕机。
这时候就可以为这段程序添加一个计数器功能,来限制一个时间点内的线程数量。
import time
import threading
s1=threading.Semaphore(5) #添加一个计数器
def test():
s1.acquire() #计数器获得锁,计数器值-1
time.sleep(2) #程序休眠2秒
print(time.ctime())
s1.release() #计数器释放锁,计数器值+1
for i in range(10):
t1=threading.Thread(target=test,args=()) #创建线程
t1.start() #启动线程
执行结果:
Thu Jul 18 14:55:54 2019
Thu Jul 18 14:55:54 2019
Thu Jul 18 14:55:54 2019
Thu Jul 18 14:55:54 2019
Thu Jul 18 14:55:54 2019
Thu Jul 18 14:55:56 2019
Thu Jul 18 14:55:56 2019
Thu Jul 18 14:55:56 2019
Thu Jul 18 14:55:56 2019
Thu Jul 18 14:55:56 2019
可以看到,由于添加的信号量初始值设定为5,所以线程以每五个进行了“分隔”。
题解
题目描述
提供一个类:
class FooBar {
public void foo() {
for (int i = 0; i < n; i++) {
print("foo");
}
}
public void bar() {
for (int i = 0; i < n; i++) {
print("bar");
}
}
}
两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。
请设计修改程序,以确保 “foobar” 被输出 n 次。
解题思路
使用两个信号量计数器,来对foo函数和bar函数分别加锁。
在调用foo函数的时候,管理foo的信号量计数器foo_lock-1,管理bar的信号量计数器bar_lock+1。
反之,在调用bar函数的时候,管理foo的信号量计数器foo_lock+1,管理bar的信号量计数器bar_lock-1。
题目解答
import threading
class FooBar:
def __init__(self, n):
self.n = n
self.foo_lock = threading.Semaphore() #添加信号量计数器,初始值为1
self.foo_lock.acquire() # 令两个计数器的值为0,造成线程阻塞
self.bar_lock = threading.Semaphore()
self.bar_lock.acquire()
def foo(self, printFoo: 'Callable[[], None]') -> None:
for i in range(self.n):
# printFoo() outputs "foo". Do not change or remove this line.
printFoo()
self.bar_lock.release()
self.foo_lock.acquire()
def bar(self, printBar: 'Callable[[], None]') -> None:
for i in range(self.n):
self.bar_lock.acquire()
# printBar() outputs "bar". Do not change or remove this line.
printBar()
self.foo_lock.release()