public static void main(String[] args) {
EvenChecker.test(new AtomicEvenGeneratorO);
}
} ///.-
Стоит еще раз подчеркнуть, что классы Atomic проектировались для построения классов из java.util.concurrent. Используйте их в своих программах только в особых случаях и только тогда, когда вы твердо уверены, что это не создаст новых проблем. В общем случае безопаснее использовать блокировки (с ключевым словом synchronized или явным созданием объектов Lock).
Критические секции
Иногда необходимо предотвратить доступ нескольких потоков только к
5упсИгоп12ес1(синхронизируемый0бъект) {
//К такому коду доступ может получить // одновременно только один поток
}
Такая конструкция иначе называется
Следующий пример сравнивает два подхода к синхронизации, показывая, насколько увеличивается время, предоставляемое потокам для доступа к объекту при использовании синхронизированной блокировки вместо синхронизации методов. Вдобавок он демонстрирует, как незащищенный класс может «выжить» в многозадачной среде, если он управляется и защищается другим классом:
//: concurrency/CriticalSection.java
// Синхронизация блоков вместо целых методов. Также демонстрирует защиту
// неприспособленного к многопоточности класса другим классом
package concurrency;
import java.util.concurrent.*:
import java.util.concurrent.atomic.*;
import java.util.*;
class Pair { // Not thread-safe private int x, y; public Pair(int x. int y) { this.x = x; this.у = у;
}
public PairO { this(0, 0); } public int getXO { return x; } public int getYO { return y; } public void incrementXO { x++; } public void incrementYO { y++; } public String toStringO {
return "x; " + x + ", y; " + y;
}
public class PairValuesNotEqualException extends RuntimeException {
public Pai rValuesNotEqual Excepti onO {
superC'Pair values not equal; " + Pair.this);
}
}
// Произвольный инвариант - обе переменные должны быть равны; public void checkStateO { if(x != у)
throw new PairValuesNotEqualException();
}
}
// Защита класса Pair внутри приспособленного к потокам класса; abstract class PairManager {
Atomiclnteger checkCounter = new AtomicInteger(O). protected Pair p = new PairO. private List
Collections synchronizedList(new ArrayList
// Создаем копию, чтобы сохранить оригинал в безопасност return new Pair(p getXO, p getYO).
}
// Предполагается, что операция занимает некоторое время protected void store(Pair р) { storage add(p), try {
TimeUnit MILLISECONDS sleep(50); } catch(InterruptedException ignore) {}
}
public abstract void incrementO.
}
// Синхронизация всего метода.
class PairManagerl extends PairManager { public synchronized void incrementO { p.incrementXO. p incrementYO. store(getPairO).
// Использование критической секции-class PairManager2 extends PairManager { public void incrementO { Pair temp.
synchronized(this) {
p incrementXO; p. incrementYO; temp = getPairO,
}
store(temp).
class PairManipulator implements Runnable { private PairManager pm; public PairManipulator(PairManager pm) { this pm = pm,
}
public void run О { while(true)
pm. increment);
}
public String toStringO {
return "Pair: " + pm.getPairO +
" checkCounter = " + pm checkCounter.get О;
}
}
class PairChecker implements Runnable { private PairManager pm; public PairChecker(PairManager pm) {
}
public class CriticalSection { // Сравнение двух подходов-static void
testApproaches(PairManager pmanl. PairManager pman2) {
ExecutorService exec = Executors newCachedThreadPool(). PairManipulator
pml = new PairManipulator(pmanl), pm2 = new PairManipulator(pman2), PairChecker
pcheckl = new PairChecker(pmanl), pcheck2 = new PairChecker(pman2), exec execute(pml), exec execute(pm2), exec execute(pcheckl); exec execute(pcheck2), try {
TimeUnit MILLISECONDS sleep(500); } catchdnterruptedException e) {
System out.printlnC'Sleep interrupted"),
}
System.out printin("pml " + pml + "\npm2: " + pm2). System exit(O),
}
public static void main(String[] args) { PairManager
pmanl = new PairManagerlO, pman2 = new PairManager2(); testApproaches(pmanl. pman2);
}
} /* Output-
pml- Pair. x. 15, у 15 checkCounter = 272565 pm2- Pair- x. 16, y: 16 checkCounter = 3956974 */// ~