LeetCode 多线程刷题笔记

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”。

阅读 — · 全站 —
🎸 我的歌单 0 首