Ну, это вопрос такого рода, где вы можете написать быструю грязную программу для оценки:
public class ThreadExperiment {
public static class CounterSync {
int count = 0;
public synchronized void increment(){
count++;
}
public synchronized void decrement(){
count--;
}
}
public static class CounterAtomic {
AtomicInteger count = new AtomicInteger();
public void increment(){
count.incrementAndGet();
}
public void decrement(){
count.decrementAndGet();
}
}
public static void main(String[] args) throws InterruptedException {
final CounterSync counterSync = new CounterSync();
final CounterAtomic counterAtomic = new CounterAtomic();
Runnable runnable = () -> {
for (int i = 0; i < 1_000_000; i++) {
int j = i & 1;
if (j == 0) {
counterSync.increment();
counterAtomic.increment();
} else {
counterSync.decrement();
counterAtomic.decrement();
}
}
};
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(runnable);
}
for (Thread t : threads)
t.start();
for (Thread t : threads)
t.join();
System.out.println("Sync count = " + counterSync.count);
System.out.println("Atomic count = " + counterAtomic.count.intValue());
}
}
В конце оба счетчика должны и будут равны 0. Удалив "синхронизированные ключевые слова, вы увидите, что все идет совершенно не так.
Так что да, оба достигают одного и того же: безопасность потоков.
Oracle документирует пример здесь: https://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html
Для этого простого класса синхронизация является приемлемым решением.Но для более сложного класса мы могли бы избежать влияния ненужной синхронизации на жизнеспособность.Замена поля int на AtomicInteger позволяет нам предотвращать помехи потоков без обращения к синхронизации
В конце концов, поведение ваших методов будет иметь значение, если вам нужна явная синхронизация или если атомные поля будутдостаточно.