×
Traktatov.net » Философия Java » Читать онлайн
Страница 364 из 395 Настройки

}

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 storage =

Collections synchronizedList(new ArrayList0). public synchronized Pair getPairO {

// Создаем копию, чтобы сохранить оригинал в безопасност 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 */// ~

Как было отмечено, класс Pair не приспособлен к работе с потоками, поскольку его инвариант (предположительно произвольный) требует равенства обоих переменных. Вдобавок, как мы уже видели в этой главе, операции инкремента небезопасны в отношении к потокам, и, так как ни один из методов не был объявлен как synchronized, мы не можем считать, что объект Pair останется неповрежденным в многопоточной программе.