Не могу понять, почему в данном примере не получается работать с 2 потоками
public class Start {
public static void main(String[] args) {
Start start = new Start();
start.init();
}
private void init() {
Game game = new Game();
MyThread myThread1 = new MyThread(game, "Ping");
MyThread myThread2 = new MyThread(game, "Pong");
myThread1.start();
myThread2.start();
}
private class MyThread extends Thread {
Game game;
public MyThread(Game game, String name) {
setName(name);
this.game = game;
}
@Override
public void run() {
while (game.isGameNotOver()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
game.kick(getName());
}
}
}
private class Game {
int counter = 0;
public synchronized void kick(String name) {
System.out.println(name + " " + counter);
counter++;
}
public boolean isGameNotOver() {
return counter < 10;
}
}
}
А именно, если Sleep стоит <=100, то возможны ситуации что 1 поток сделает всю работы. Если поставить 500, то проблема перестанет наблюдаться.
Пытался сделать по аналогии с этой задачей Но только убрал синглтон и проверку по имени потока. Явно ведь, проверка имени это какая-то.... не обычность.
DL: первый раз работаю с синхронизацией в java, так что критика приветствуется.
Я немного прокачал класс Game
private class Game {
volatile int counter = 0;
volatile boolean isPing = true;
public synchronized void waitFor(boolean isPing) {
while (isPing() != isPing && isGameNotOver()) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void kick(boolean isPing) {
System.out.println((isPing ? "Ping": "Pong") + " " + counter);
counter++;
this.isPing = !isPing;
this.notifyAll();
}
public boolean isPing() {
return isPing;
}
public boolean isGameNotOver() {
return counter < 100;
}
}
С такой прокачкой, мы видим, что поток будет ждать нужного состояния игры, чтобы сделать ход.
private class MyThread extends Thread {
Game game;
private boolean isPing() {
return "Ping".equals(getName());
}
public MyThread(Game game, String name) {
setName(name);
this.game = game;
}
@Override
public void run() {
while (game.isGameNotOver()) {
game.waitFor(isPing());
if (game.isGameNotOver())
game.kick(isPing());
}
}
}
Как вы видите, тут мы не завсим от таймингов, а условие изменения состояния игры детерминировано. При таких условиях мы даже можем добавить игроков и все равно увидим, что Ping и Pong будут корректно чередоваться
private void init() {
Game game = new Game();
MyThread myThread1 = new MyThread(game, "Ping");
MyThread myThread2 = new MyThread(game, "Pong");
MyThread myThread3 = new MyThread(game, "Ping");
MyThread myThread4 = new MyThread(game, "Pong");
myThread1.start();
myThread2.start();
myThread3.start();
myThread4.start();
}
Вывод
Ping 0
Pong 1
...
Ping 96
Pong 97
Ping 98
Pong 99
Минимальный пинг понг
public class PingPong {
public static void main(String[] args) {
final var numberOfPlays = 20;
new Thread(() -> play("ping", numberOfPlays)).start();
new Thread(() -> play("pong", numberOfPlays)).start();
}
private static synchronized void play(String name, int numberOfPlays) {
while (true) {
System.out.println(name);
try {
PingPong.class.notify();
if (--numberOfPlays == 0) {
break;
} else {
PingPong.class.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
У меня есть своя библиотека servicejar которую я подключаю через nexus
Пробую делать REST сервис на Spring Boot + Firebird 30
По нажатии на кнопку хочу создать одно диалоговое окноВот код класса