Чтение онлайн

на главную - закладки

Жанры

Философия Java3

Эккель Брюс

Шрифт:

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 останется неповрежденным в многопоточной программе.

Представьте, что вы получили готовый класс Pair, который должен работать в многопоточных условиях. Класс PairManager хранит объекты Pair и управляет любым доступом к ним. Заметьте, что единственными открытыми (public) методами являются getPair, объявленный как synchronized, и абстрактный метод doTask. Синхронизация этого метода будет осуществлена при его реализации.

this pm = pm.

}

public void run {

while(true) {

pm checkCounter.i ncrementAndGet; pm getPa>r checkState,

Структура класса PairManager, в котором часть функциональности базового класса реализуется одним или несколькими абстрактными методами, определенными производными классами, называется на языке паттернов проектирования «шаблонным методом». Паттерны проектирования позволяют инкапсулировать изменения в коде — здесь изменяющаяся часть представлена методом increment. В классе PairManagerl метод increment полностью синхронизирован, в то время как в классе PairManager2 только часть его была синхронизирована посредством синхронизируемой блокировки. Обратите внимание еще раз, что ключевые слова synchronized не являются частью сигнатуры метода и могут быть добавлены во время переопределения.

Метод store

добавляет объект Pair в синхронизированный контейнер Array-List, поэтому операция является потоково-безопасной. Следовательно, в защите он не нуждается, поэтому его вызов размещен за пределами синхронизируемого блока.

Класс PairManipulator создается для тестирования двух разновидностей Pair-Manager: метод increment вызывается в задаче в то время, как в другой задаче работает PairChecker. Метод main создает два объекта PairManipulator и дает им поработать в течение некоторого времени, после чего выводятся результаты по каждому PairManipulator.

Для создания критических секций также можно воспользоваться явно созданными объектами Lock:

//: concurrency/ExplicitCriticalSection.java

// Использование объектов Lock для создания критических секций.

package concurrency;

import java.util.concurrent.locks.*;

// Синхронизация целого метода: class ExplicitPairManagerl extends PairManager { private Lock lock = new ReentrantLockO; public synchronized void incrementO { lock lockO; try {

p.incrementXO; p. incrementYO; store(getPairO); } finally {

lock.unlock О;

}

}

}

// Использование критической секции: class ExplicitPairManager2 extends PairManager { private Lock lock = new ReentrantLockO: public void incrementO { Pair temp; lock.lockO: try {

p.incrementXO;

р incrementYO. temp = getPairO. } finally {

lock unlock О,

}

store(temp),

public class ExplicitCriticalSection {

public static void main(String[] args) throws Exception { PairManager

pmanl = new ExplicitPairManagerK), pman2 = new ExplicitPairManager2, CriticalSection.testApproaches(pmanl, pman2);

}

} /* Output

pml. Pair: x: 15, у 15 checkCounter = 174035 pm2: Pair- x- 16, у 16 checkCounter = 2608588 *///.-

В программе создаются новые типы PairManager с явным использованием объектов Lock. ExplicitPairManager2 демонстрирует создание критической секции с использованием объекта Lock; вызов store находится вне критической секции.

Синхронизация по другим объектам

Блоку synchronized необходимо передать объект, который будет использоваться для синхронизации. Чаще всего наиболее естественно передавать текущий объект, для которого был вызван метод synchronized(this), и именно такой подход применен в классе PairManager2. Таким образом, при входе в синхронизируемый блок другие синхронизированные методы объекта вызвать будет нельзя. Действие синхронизации по this фактически заключается в сужении области синхронизации.

Иногда вам нужно что-то иное, и в таких ситуациях вы создаете отдельный объект и выполняете синхронизацию, привлекая его. В таких случаях необходимо позаботиться о том, чтобы все операции синхронизировались по одному и тому же объекту. Следующий пример показывает, как два потока входят в объект, когда методы этого объекта синхронизированы различными блокировками:

Поделиться:
Популярные книги

Девочка из прошлого

Тоцка Тала
3. Айдаровы
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Девочка из прошлого

Третий Генерал: Том X

Зот Бакалавр
9. Третий Генерал
Фантастика:
городское фэнтези
аниме
сказочная фантастика
попаданцы
5.00
рейтинг книги
Третий Генерал: Том X

Эволюционер из трущоб. Том 7

Панарин Антон
7. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 7

Я еще граф. Книга #8

Дрейк Сириус
8. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
5.00
рейтинг книги
Я еще граф. Книга #8

Поводырь

Щепетнов Евгений Владимирович
3. Ботаник
Фантастика:
фэнтези
6.17
рейтинг книги
Поводырь

Законник Российской Империи. Том 2

Ткачев Андрей Юрьевич
2. Словом и делом
Фантастика:
городское фэнтези
альтернативная история
аниме
дорама
6.40
рейтинг книги
Законник Российской Империи. Том 2

Личный аптекарь императора

Карелин Сергей Витальевич
1. Личный аптекарь императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Личный аптекарь императора

Государь

Кулаков Алексей Иванович
3. Рюрикова кровь
Фантастика:
мистика
альтернативная история
историческое фэнтези
6.25
рейтинг книги
Государь

Хозяин Стужи

Петров Максим Николаевич
1. Злой Лед
Фантастика:
аниме
фэнтези
попаданцы
7.00
рейтинг книги
Хозяин Стужи

Как прорастают зерна

Волкова Дарья
Любовные романы:
современные любовные романы
7.00
рейтинг книги
Как прорастают зерна

Хозяин Теней 3

Петров Максим Николаевич
3. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Хозяин Теней 3

Лейтенант. Назад в СССР. Книга 8. Часть 1

Гаусс Максим
8. Второй шанс
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Лейтенант. Назад в СССР. Книга 8. Часть 1

Наследие Маозари

Панежин Евгений
1. Наследие Маозари
Фантастика:
рпг
попаданцы
аниме
5.80
рейтинг книги
Наследие Маозари

Курс 1. Сентябрь

Фокс Гарри
1. Маркатис
Фантастика:
аниме
фэнтези
сказочная фантастика
5.00
рейтинг книги
Курс 1. Сентябрь