Есть несколько проблем с вашим кодом:
Thread.join метод работает, только если поток запущен, иначе он ничего не делает.Поэтому вы должны изменить порядок своего кода, но если вы просто переместите метод join после start , при запуске первого потока вызовом CounterThread.start , основного потокабудет ожидать окончания запущенного потока, заблокированного в методе Thread.join , и только после этого продолжит запуск второго.Решением является создание дополнительного метода в классе CounterThread , который будет вызываться после запуска обоих потоков:
public void waitFinish() throws InterruptedException {
thread.join();
}
synchronized (this) isсинхронизация на экземпляре CounterThread , который был создан при вызове new CounterThread (...) , но у вас есть два экземпляра, поэтому каждый будет синхронизироваться с другим объектом.Для синхронизации для работы вам необходимо использовать общий экземпляр объекта, в этом случае вы можете использовать общий counterObj .
. Гарантированы только методы AtomicInteger .быть потокобезопасным, поэтому после проверки, достигнута ли граница за пределами синхронизированного блока, при входе в синхронизированный блок значение уже может быть изменено другим потоком.Поэтому необходимо выполнить повторную проверку внутри синхронизированного блока ИЛИ, чтобы сначала выполнить синхронизацию с общей блокировкой ( counterObj ) перед проверкой и увеличением.
while (true) {
synchronized (counterObj) {
if (counterObj.get() < bound)
counterObj.incrementAndGet();
else break;
}
}
Обратите внимание, что AtomicInteger синхронизированные методы класса теперь не помогают, но поскольку это изменчивый объект, он помогает использовать его в качестве общей блокировки.Если вместо этого вы использовали Integer , будучи неизменным, при увеличении его будет создан новый экземпляр.Так что теперь единственная функция - это обертка, содержащая целочисленный результат.
Собираем все вместе:
public class Application {
public static void main(String[] args) {
Application app = new Application();
try {
app.launch();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void launch() throws InterruptedException {
int increments = 100;
AtomicInteger counterObj = new AtomicInteger(0);
CounterThread th1 = new CounterThread("1", counterObj, increments);
CounterThread th2 = new CounterThread("2", counterObj, increments);
th1.start();
th2.start();
th1.waitFinish();
th2.waitFinish();
System.out.println(counterObj.get());
}
}
public class CounterThread implements Runnable {
private final String threadID;
private AtomicInteger counterObj;
private int bound;
private Thread thread;
public CounterThread(String threadID, AtomicInteger counter, int bound) {
this.threadID = threadID;
this.counterObj = counter;
this.bound = bound;
}
@Override
public void run() {
while (true) {
synchronized (counterObj) {
if (counterObj.get() < bound)
counterObj.incrementAndGet();
else break;
}
}
System.out.println("Thread " + threadID + " finished");
}
public void start() throws InterruptedException {
thread = new Thread(this, threadID);
thread.start();
}
public void waitFinish() throws InterruptedException {
thread.join();
}
}