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

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

Жанры

Философия Java3

Эккель Брюс

Шрифт:

У/ concurrency/SyncObject java // Синхронизация по другому объекту, import static net.mindview util.Print *;

class Dual Synch {

private Object syncObject = new Object О; public synchronized void f {

for(int i = 0; i < 5; i++) { printCfO"); Thread.yieldO;

}

}

public void gO { продолжение &

synchronizedsyncObject) {

for(int i = 0; i < 5; i++) { printC'gO"); Thread.yieldO;

public class SyncObject {

public static void main(String[] args) {

final Dual Synch ds = new DualSynchO; new ThreadO {

public void run { ds.fO;

}

}.startO; ds.gO;

}

} /* Output:

go

fO

go f go fo go fo go f *///:-

Метод f

класса DualSync синхронизируется по объекту this (синхронизируя метод целиком), а метод g использует синхронизацию посредством объекта syncObject. Таким образом, два варианта синхронизации независимы. Демонстрируется этот факт методом main, в котором создается поток Thread с вызовом метода f. Поток main после этого вызывает метод д. Из результата работы программы видно, что оба метода работают одновременно и ни один из них не блокируется соседом.

Локальная память потока

Второй механизм предотвращения конфликтов доступа к общим ресурсам основан на исключении их совместного использования. Локальная память потока представляет собой механизм автоматического выделения разных областей памяти для одной переменной во всех потоках, использующих объект. Следовательно, если пять потоков используют объект с переменной х, для х будет сгенерировано пять разных областей памяти. Фактически поток связывается с некоторым состоянием.

За выделение локальной памяти потоков и управление ею отвечает класс java.lang.ThreadLocal:

//: concurrency/ThreadLocalVariableHolder.java

// Автоматическое выделение собственной памяти каждому потоку.

import java util.concurrent.*, import java util *,

class Accessor implements Runnable { private final int id. public Accessor(int idn) { id = idn; } public void run {

while( IThread.currentThreadO islnterrupted) { ThreadLocalVariableHolder incrementO; System out println(this). Thread.yieldO.

}

}

public String toStringO {

return "#" + id + " " +

ThreadLocalVari ableHolder.get.

public class ThreadLocalVariableHolder {

private static ThreadLocal<Integer> value = new ThreadLocal<Integer> {

private Random rand = new Random(47). protected synchronized Integer initialValueO { return rand.nextlnt(lOOOO).

}

}:

public static void incrementO {

value.set(value.get + 1).

}

public static int get О { return value getO. } public static void main(String[] args) throws Exception {

ExecutorService exec = Executors newCachedThreadPoolО. for(int i = 0. i < 5. i++)

exec.execute(new Accessor(i)). TimeUnit.SECONDS.sleep(3); // Небольшая задержка exec shutdownNowO, // Выход из всех объектов Accessor

}

} /* Output #0 9259 #1- 556 #2. 6694 #3- 1862 #4: 962 #0: 9260 #1- 557 #2: 6695 #3: 1863 #4: 963

*///:-

Объекты ThreadLocal обычно хранятся в статических полях. Если вы создаете объект ThreadLocal, для обращения к содержимому объекта можно использовать только методы get и set. Метод get возвращает копию объекта, ассоциированного с потоком, a set сохраняет свой аргумент в объекте потока, возвращая ранее хранившийся объект. Их использование продемонстрировано

в методах increment и get класса ThreadLocalVariableHolder. Обратите внимание: методы increment^) и get не синхронизированы, потому что ThreadLocal не гарантирует отсутствия «ситуации гонки».

Взаимодействие между потоками

Итак, мы выяснили, что потоки способны конфликтовать друг с другом, и разобрались с тем, как предотвратить такие конфликты. Следующим шагом должно стать изучение возможностей взаимодействия между потоками. Ключевым моментом в этом процессе является подтверждение связи, безопасно реализуемое методами wait и notify класса Object. В многопоточной библиотеке Java SE5 также присутствуют объекты Condition с методами await и signal. Мы рассмотрим некоторые возникающие проблемы и их решения.

Методы wait и notifyAII

Метод wait ожидает изменения некоторого условия, неподконтрольного для текущего метода. Довольно часто это условие изменяется в результате выполнения другой задачи. Активное ожидание, то есть проверка условия в цикле, нежелательно из-за неэффективного расходования вычислительных ресурсов. Таким образом, метод wait обеспечивает механизм синхронизации действий между задачами.

Важно понять, что метод sleep не освобождает объект блокировки. С другой стороны, метод wait снимает блокировку с объекта, тем самым позволяя остальным потокам вызывать другие синхронизированные методы объекта во время выполнения wait. Это очень важно, потому что обычно именно «другие» методы приводят к изменению условия и активизации приостановленной задачи.

Существует две формы метода wait. У первой формы аргумент имеет такой же смысл, как и аргумент метода sleep: это продолжительность интервала в миллисекундах, на который приостанавливается выполнение потока. Разница между методами состоит в следующем:

1. При выполнении метода wait блокируемый объект освобождается.

2. Выйти из состояния ожидания, установленного wait, можно двумя способами: с помощью уведомления notify или notifyAU либо по истечении срока ожидания.

Вторая, более распространенная форма вызывается без аргументов. Эта версия метода wait заставит поток простаивать, пока не придет уведомление notify или notifyAll.

Пожалуй, самое интересное в методах wait, notify и notifyAU — их принадлежность к общему классу Object, а не к классу потоков Thread. Хотя это и кажется немного нелогичным — размещение чего-то, относящегося исключительно к механизму потоков, в общем базовом классе — на самом деле это решение совершенно оправдано, поскольку означенные методы манипулируют блокировками, которые являются частью любого объекта. В результате ожидание (wait) может использоваться в любом синхронизированном методе, независимо от того, наследует ли класс от Thread или реализует Runnable. Вообще говоря, единственное место, где допустимо вызывать метод wait, — это синхронизированный метод или блок (метод sleep можно вызывать в любом месте, так как он не манипулирует блокировкой). Если вызвать метод wait или notify в обычном методе, программа скомпилируется, однако при ее выполнении возникнет исключение IllegalMonitorStateException с несколько туманным сообщением «текущий поток не является владельцем» («current thread not owner»). Это сообщение означает, что поток, востребовавший методы wait, notify или notifyAll, должен быть «хозяином» блокируемого объекта (овладеть объектом блокировки) перед вызовом любого из данных методов.

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

Газлайтер. Том 38

Володин Григорий Григорьевич
38. История Телепата
Фантастика:
городское фэнтези
аниме
попаданцы
6.20
рейтинг книги
Газлайтер. Том 38

Сборник статей и интервью 2009г (v1.23)

Кагарлицкий Борис Юльевич
Научно-образовательная:
политика
5.00
рейтинг книги
Сборник статей и интервью 2009г (v1.23)

Система Возвышения. (цикл 1-8) - Николай Раздоров

Раздоров Николай
Система Возвышения
Фантастика:
боевая фантастика
4.65
рейтинг книги
Система Возвышения. (цикл 1-8) - Николай Раздоров

Том 10. Мертвое озеро

Некрасов Николай Алексеевич
10. Собрание сочинений в пятнадцати томах
Проза:
русская классическая проза
5.00
рейтинг книги
Том 10. Мертвое озеро

"Фантастика 2024-164". Компиляция. Книги 1-25

Злотников Роман Валерьевич
Фантастика 2024. Компиляция
Фантастика:
боевая фантастика
попаданцы
альтернативная история
аниме
фэнтези
5.00
рейтинг книги
Фантастика 2024-164. Компиляция. Книги 1-25

#Бояръ-Аниме. Газлайтер. Том 13

Володин Григорий Григорьевич
13. История Телепата
Фантастика:
боевая фантастика
аниме
попаданцы
фэнтези
7.33
рейтинг книги
#Бояръ-Аниме. Газлайтер. Том 13

Резонанс Ци. Дилогия

Орлов Андрей Юрьевич
Резонанс Ци
Фантастика:
постапокалипсис
рпг
уся
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Резонанс Ци. Дилогия

Время умирать

Смит Уилбур
7. Кортни
Приключения:
прочие приключения
8.33
рейтинг книги
Время умирать

Жизнь способ употребления

Перек Жорж
Проза:
современная проза
5.00
рейтинг книги
Жизнь способ употребления

Рассвет русского царства. Книга 2

Грехов Тимофей
2. Новая Русь
Фантастика:
альтернативная история
попаданцы
историческое фэнтези
5.00
рейтинг книги
Рассвет русского царства. Книга 2

Я князь. Книга XVIII

Дрейк Сириус
18. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я князь. Книга XVIII

Правь, Британия!

дю Морье Дафна
Проза:
современная проза
6.25
рейтинг книги
Правь, Британия!

Сочинения

Брюсов Валерий Яковлевич
Проза:
русская классическая проза
5.00
рейтинг книги
Сочинения

Королевский казначей

Костейн Томас
Приключения:
исторические приключения
6.00
рейтинг книги
Королевский казначей