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

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

Жанры

Программирование на Java
Шрифт:

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

Последовательность команд подчиняется следующим правилам:

* все действия, выполняемые одним потоком, строго упорядочены, т.е. выполняются одно за другим;

* все действия, выполняемые с одной переменной в основном хранилище памяти, строго упорядочены, т.е. следуют

одно за другим.

За исключением некоторых дополнительных очевидных правил, больше никаких ограничений нет. Например, если поток изменил значение сначала одной, а затем другой переменной, то эти изменения могут быть переданы в основное хранилище в обратном порядке.

Поток создается с чистой рабочей памятью и должен перед использованием загрузить все необходимые переменные из основного хранилища. Любая переменная сначала создается в основном хранилище и лишь затем копируется в рабочую память потоков, которые будут ее применять.

Таким образом, потоки никогда не взаимодействуют друг с другом напрямую, только через главное хранилище.

Модификатор volatile

При объявлении полей объектов и классов может быть указан модификатор volatile. Он устанавливает более строгие правила работы со значениями переменных.

Если поток собирается выполнить команду use для volatile переменной, то требуется, чтобы предыдущим действием с этой переменной было обязательно load, и наоборот – операция load может выполняться только перед use. Таким образом, переменная и главное хранилище всегда имеют самое последнее значение этой переменной.

Аналогично, если поток собирается выполнить команду store для volatile переменной, то требуется, чтобы предыдущим действием над этой переменной было обязательно assign, и наоборот – операция assign может выполняться, только если следующей будет store. Таким образом, переменная и главное хранилище всегда имеют самое последнее значение этой переменной.

Наконец, если проводятся операции над несколькими volatile переменными, то передача соответствующих изменений в основное хранилище должна проводиться строго в том же порядке.

При работе с обычными переменными компилятор имеет больше пространства для маневра. Например, при благоприятных обстоятельствах может оказаться возможным предсказать значение переменной, заранее вычислить и сохранить его, а затем в нужный момент использовать уже готовым.

Следует обратить внимание на два 64-разрядных типа, double и long. Поскольку многие платформы поддерживают лишь 32-битную память, величины этих типов рассматриваются как две переменные и все описанные действия выполняются независимо для двух половинок таких значений. Конечно, если производитель виртуальной машины считает возможным, он может обеспечить атомарность операций и над этими типами. Для volatile переменных это является обязательным требованием.

Блокировки

В основном хранилище для каждого объекта поддерживается блокировка ( lock ), над которой можно произвести два действия – установить ( lock ) и снять ( unlock ). Только один поток в один момент

времени может установить блокировку на некоторый объект. Если до того, как этот поток выполнит операцию unlock, другой поток попытается установить блокировку, его выполнение будет приостановлено до тех пор, пока первый поток не отпустит ее.

Операции lock и unlock накладывают жесткое ограничение на работу с переменными в рабочей памяти потока. После успешно выполненного lock рабочая память очищается и все переменные необходимо заново считывать из основного хранилища. Аналогично, перед операцией unlock необходимо все переменные сохранить в основном хранилище.

Важно подчеркнуть, что блокировка является чем-то вроде флага. Если блокировка на объект установлена, это не означает, что данным объектом нельзя пользоваться, что его поля и методы становятся недоступными,– это не так. Единственное действие, которое становится невозможным,– установка этой же блокировки другим потоком, до тех пор, пока первый поток не выполнит unlock.

В Java-программе для того, чтобы воспользоваться механизмом блокировок, существует ключевое слово synchronized. Оно может быть применено в двух вариантах – для объявления synchronized -блока и как модификатор метода. В обоих случаях действие его примерно одинаковое.

Synchronized -блок записывается следующим образом:

synchronized (ref) {

...

}

Прежде, чем начать выполнять действия, описанные в этом блоке, поток обязан установить блокировку на объект, на который ссылается переменная ref (поэтому она не может быть null ). Если другой поток уже установил блокировку на этот объект, то выполнение первого потока приостанавливается до тех пор, пока не удастся выполнить операцию lock.

После этого блок выполняется. При завершении исполнения (как успешном, так и в случае ошибок) производится операция unlock, чтобы освободить объект для других потоков.

Рассмотрим пример:

public class ThreadTest implements Runnable {

private static ThreadTest

shared = new ThreadTest;

public void process {

for (int i=0; i<3; i++) {

System.out.println(

Thread.currentThread.

getName+" "+i);

Thread.yield;

}

}

public void run {

shared.process;

}

public static void main(String s[]) {

for (int i=0; i<3; i++) {

new Thread(new ThreadTest,

"Thread-"+i).start;

}

}

}

В этом простом примере три потока вызывают метод у одного объекта, чтобы тот распечатал три значения. Результатом будет:

Thread-0 0

Thread-1 0

Thread-2 0

Thread-0 1

Thread-2 1

Thread-0 2

Thread-1 1

Thread-2 2

Thread-1 2

То есть все потоки одновременно работают с одним методом одного объекта. Заключим обращение к методу в synchronized -блок:

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

Вдовье счастье

Брэйн Даниэль
1. Ваш выход, маэстро!
Фантастика:
попаданцы
историческое фэнтези
фэнтези
5.00
рейтинг книги
Вдовье счастье

Крепость над бездной

Лисина Александра
4. Гибрид
Фантастика:
боевая фантастика
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Крепость над бездной

Прорвемся, опера! Книга 4

Киров Никита
4. Опер
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Прорвемся, опера! Книга 4

Возвышение Меркурия. Книга 12

Кронос Александр
12. Меркурий
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 12

Черный дембель. Часть 2

Федин Андрей Анатольевич
2. Черный дембель
Фантастика:
попаданцы
альтернативная история
4.25
рейтинг книги
Черный дембель. Часть 2

Кодекс Охотника. Книга XV

Винокуров Юрий
15. Кодекс Охотника
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XV

Как я строил магическую империю

Зубов Константин
1. Как я строил магическую империю
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Как я строил магическую империю

Звездная Кровь. Изгой

Елисеев Алексей Станиславович
1. Звездная Кровь. Изгой
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Звездная Кровь. Изгой

Камень. Книга 3

Минин Станислав
3. Камень
Фантастика:
фэнтези
боевая фантастика
8.58
рейтинг книги
Камень. Книга 3

Монстр из прошлого тысячелетия

Еслер Андрей
5. Соприкосновение миров
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Монстр из прошлого тысячелетия

Найди меня Шерхан

Тоцка Тала
3. Ямпольские-Демидовы
Любовные романы:
современные любовные романы
короткие любовные романы
7.70
рейтинг книги
Найди меня Шерхан

Релокант

Ascold Flow
1. Релокант в другой мир
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Релокант

Мужчина моей судьбы

Ардова Алиса
2. Мужчина не моей мечты
Любовные романы:
любовно-фантастические романы
8.03
рейтинг книги
Мужчина моей судьбы

Ученик. Книга вторая

Первухин Андрей Евгеньевич
2. Ученик
Фантастика:
фэнтези
5.40
рейтинг книги
Ученик. Книга вторая