Stack Overflow на русском Asked on January 11, 2021
Всем привет, задача вот такая в общем: есть класс Foo и 3 метода, нужно создать три потока, каждый из которых вызывает по одному методу, и создать так, чтобы они последовательно написали "firstsecondthird"
class Foo{
private static final Semaphore printOne = new Semaphore(1);
private static final Semaphore printTwo = new Semaphore(1);
private static final Semaphore printThree = new Semaphore(1);
public Foo() throws InterruptedException {
printTwo.acquire();
printThree.acquire();
}
public void printFirst() throws InterruptedException {
printOne.acquire();
System.out.print("first");
printTwo.release();
}
public void printSecond() throws InterruptedException {
printTwo.acquire();
System.out.print("second");
printThree.release();
}
public void printThird() throws InterruptedException {
printThree.acquire();
System.out.print("third");
printOne.release();
}
}
public class Starter {
public static void main(String[] args) throws InterruptedException {
new Thread(new Thread1()).start();
new Thread(new Thread2()).start();
new Thread(new Thread3()).start();
}
}
class Thread1 implements Runnable{
@Override
public void run() {
try {
new Foo().printFirst();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Thread2 implements Runnable{
@Override
public void run() {
try {
new Foo().printSecond();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Thread3 implements Runnable{
@Override
public void run() {
try {
new Foo().printThird();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Данный код успевает создает только один поток Thread1 и печатает "first", а дальше бесконечно ожидает. Не могу понять почему это происходит и как это исправить.
PS может, как-то получше можно написать, чтобы поток вызывал один метод в классе Foo?
В вашем коде ошибка возникает потому, что семафоры статические, и захватываются в конструкторе класса Foo
. А создаете вы три экземпляра этого класса. По-этому, первый экземпляр создается нормально, а два других вызова конструктора блокируются и до вызовов метода print
дело не доходит.
Исправить можно, либо сделав захват семафоров тоже статическим:
static {
try {
printTwo.acquire();
printThree.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public Foo() throws InterruptedException {
}
Либо создавать один экземпляр класса Foo
и передавать его в конструкторы Thread1
и т.д.
Еще одни вариант, это использовать CountDownLatch
. Он не требует предварительного захвата. Поток, который дошел до точки синхронизации сообщает об этом другому потоку:
static CountDownLatch firstFinished = new CountDownLatch(1);
public void printFirst() throws InterruptedException {
System.out.print("first");
firstFinished.countDown();
}
public void printSecond() throws InterruptedException {
firstFinished.await();
System.out.print("second");
secondFinished.countDown();
}
Но лучше, конечно, не накладывать статические блокировки в нестатических методах. Семафоры (или CountDownLatch
-и) лучше сделать нестатическими и работать с одним экземпляром Foo
во всех потоках:
public class Starter {
public static void main(String[] args) throws InterruptedException {
Foo foo = new Foo();
new Thread(new Thread1(foo)).start();
new Thread(new Thread2(foo)).start();
new Thread(new Thread3(foo)).start();
}
}
class Thread1 implements Runnable{
private Foo foo;
public Thread1(Foo foo) {
this.foo = foo;
}
@Override
public void run() {
try {
foo.printFirst();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Correct answer by Roman Konoval on January 11, 2021
Вы не выложили полного условия задачи, поэтому предположу, что использовать семафоры вы решили сами. Самое простое решение - это использовать только механизмы треда.
public static void main(String[] args) throws InterruptedException {
Thread1 thread1 = new Thread1();
thread1.start();
thread1.join();
Thread2 thread2 = new Thread2();
thread2.start();
thread2.join();
Thread3 thread3 = new Thread3();
thread3.start();
}
static class Foo {
public void print(String message) {
System.out.print(message);
}
}
static class Thread1 extends Thread {
@Override
public void run() {
new Foo().print("first");
}
}
static class Thread2 extends Thread {
@Override
public void run() {
new Foo().print("second");
}
}
static class Thread3 extends Thread {
@Override
public void run() {
new Foo().print("third");
}
}
Answered by DmitryD on January 11, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP