55. Чередование вывода foo
и bar
#
Условие задачи:
📌 Дана класс FooBar
, в котором методы foo()
и bar()
выводят строки "foo"
и "bar"
по n
раз каждый. Одна и та же инстанция передаётся двум потокам:
- Поток A вызывает
foo()
- Поток B вызывает
bar()
Необходимо изменить реализацию так, чтобы вывод был чередованием "foobarfoobar..."
ровно n
раз.
Код:
import java.util.concurrent.Semaphore;
class FooBar {
private final int n;
// TODO: добавить синхронизацию
public FooBar(int n) {
this.n = n;
// TODO: инициализация
}
public void foo() throws InterruptedException {
for (int i = 0; i < n; i++) {
// TODO: ожидание и вывод "foo"
System.out.print("foo");
// TODO: разрешить bar()
}
}
public void bar() throws InterruptedException {
for (int i = 0; i < n; i++) {
// TODO: ожидание и вывод "bar"
System.out.print("bar");
// TODO: разрешить foo()
}
}
}
Спойлеры к решению
Подсказки
💡 Используйте два Semaphore
:
semFoo
с начальными разрешениями = 1,semBar
с начальными разрешениями = 0.
💡 В методеfoo()
перед выводом вызывайтеsemFoo.acquire()
, после —semBar.release()
.
💡 В методеbar()
перед выводом вызывайтеsemBar.acquire()
, после —semFoo.release()
.
💡 Это гарантирует строгую чередующуюся последовательность.
Решение
import java.util.concurrent.Semaphore;
class FooBar {
private final int n;
private final Semaphore semFoo = new Semaphore(1);
private final Semaphore semBar = new Semaphore(0);
public FooBar(int n) {
this.n = n;
}
public void foo() throws InterruptedException {
for (int i = 0; i < n; i++) {
semFoo.acquire(); // ждём разрешения для foo
System.out.print("foo");
semBar.release(); // разрешаем bar
}
}
public void bar() throws InterruptedException {
for (int i = 0; i < n; i++) {
semBar.acquire(); // ждём разрешения для bar
System.out.print("bar");
semFoo.release(); // разрешаем foo
}
}
// Тестирование с двумя потоками
public static void main(String[] args) {
int n = 5;
FooBar fb = new FooBar(n);
Thread t1 = new Thread(() -> {
try {
fb.foo();
} catch (InterruptedException ignored) {}
});
Thread t2 = new Thread(() -> {
try {
fb.bar();
} catch (InterruptedException ignored) {}
});
t1.start();
t2.start();
}
}