LeetCode 多线程刷题笔记
目录:LeetCode 索引
交替打印 FooBar(LeetCode 1115)
两个线程共用一个 FooBar 实例,一个线程调用 foo()、另一个调用 bar(),确保 "foobar" 被输出 n 次。
- n = 1 →
"foobar" - n = 2 →
"foobarfoobar"
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"); }
}
}
知识点
线程间的同步可以通过锁、信号量和信号来完成。
信号量(Semaphore)
负责协调各个线程,使它们正确、合理地使用公共资源。信号量通过一个计数器控制对共享资源的访问,值是非负整数:
- 计数器 > 0 则访问被允许,计数器减 1;
- 计数器为 0 则访问被禁止,试图通过它的线程进入等待状态。
分类:
- 二进制信号量:只允许取 0 或 1 值,同时只能被一个线程获取;
- 整型信号量:取值是整数,可被多个线程获得,直到值变为 0;
- 记录型信号量:除一个整数值 value(计数)外,还有一个等待队列 List(阻塞在该信号量上的线程标识)。释放一个、值加一后,系统自动从等待队列唤醒一个等待线程获得信号量,信号量再减一。
Python3 版(两个信号量)
用两个信号量分别控制两个线程:foo_semaphore 初始为 1(先执行 foo),bar_semaphore 初始为 0(先阻塞 bar)。acquire() 在计数器为 0 时会阻塞等待,直到计数器 > 0 被唤醒。
from threading import Semaphore
class FooBar:
def __init__(self, n):
self.n = n
# 初始化两个信号量,分别控制两个线程。
# 若信号量计数器为 0,acquire() 会阻塞等待,直到 >0 才被唤醒。
self.foo_semaphore = Semaphore(1)
self.bar_semaphore = Semaphore(0)
def foo(self, printFoo: 'Callable[[], None]') -> None:
for i in range(self.n):
# foo_semaphore 初始化为 1,因此 acquire() 立即返回 True
if self.foo_semaphore.acquire():
printFoo()
# 释放 bar 的通行证,唤醒 bar 线程
self.bar_semaphore.release()
def bar(self, printBar: 'Callable[[], None]') -> None:
for i in range(self.n):
# bar_semaphore 初始化为 0,acquire 时阻塞,
# 直到 foo 中 release() 使计数器 >0 才被唤醒
if self.bar_semaphore.acquire():
printBar()
# 释放 foo 的通行证,进入下一轮 foo
self.foo_semaphore.release()
工作过程:foo 先获得通行证打印 “foo” 并释放 bar;bar 被唤醒打印 “bar” 并释放 foo;如此交替,保证每次输出顺序固定为 “foobar”。
阅读 —
·
全站 —