Синхронизация. Пакет java.io предоставляет классы, которые позволяют выполнять конвертацию между символьными потоками Unicode и байтовыми потоками не-Unicode текста
Пакет java.io предоставляет классы, которые позволяют выполнять конвертацию между символьными потоками Unicode и байтовыми потоками не-Unicode текста. При помощи класса InputStreamReader существует возможность преобразовывать байтовые потоки в символьные потоки. Для перевода символьных потоков в байтовые потоки используется класс OutputStreamWriter.
При создании объектов InputStreamReader и OutputStreamWriter, задается байтовая кодировка, в которую необходимо выполнить преобразование. Например, чтобы перевести текстовый файл в кодировке UTF-8 в Unicode, необходимо сделать следующее:
FileInputStream fis = new FileInputStream("test.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF8");
Если не указать идентификатор кодировки, InputStreamReader и OutputStreamWriter будут обращаться к кодировке по умолчанию. Вы можете определить кодировку, используемую InputStreamReader или OutputStreamWriter, вызвав метод getEncoding, таким образом:
InputStreamReader defaultReader = new InputStreamReader(fis);
String defaultEncoding = defaultReader.getEncoding();
Синхронизация
Чтобы класс мог использоваться в многопоточной среде, необходимо объявить соответствующие методы с атрибутом synchronized. Если некоторый поток вызывает метод synchronized, то происходит блокировка объекта. Вызов метода synchronized того же объекта другим потоком будет приостановлен до снятия блокировки.
Синхронизация приводит к тому, что выполнение двух потоков становится взаимно исключающим по времени. Проблема вложенных вызовов решается очевидным образом: если синхронизированный метод вызывается для объекта, который ранее был заблокирован тем же самым потоком, то метод выполняется, однако блокировка не снимается вплоть до выхода из самого внешнего синхронизированного метода.
Синхронизация решает проблему, возникающую в нашем примере: если действия выполняются в синхронизированном методе, то при попытке обращения к объекту со стороны второго потока в тот момент, когда с объектом работает первый поток, доступ будет отложен до снятия блокировки.
Приведем пример того, как мог бы выглядеть класс Account, спроектированный для работы в многопоточной среде:
class Account {
private double balance;
public Account(double initialDeposit) {
balance = initialDeposit;
}
public synchronized double getBalance() {
return balance;
}
public synchronized void deposit(double amount) {
balance += amount;
}
}
А теперь мы объясним, что же означает понятие «соответствующие » применительно к синхронизированным методам.
Конструктор не обязан быть synchronized, поскольку он выполняется только при создании объекта, а это может происходить только в одном потоке для каждого вновь создаваемого объекта. Поле balance защищено от любых несинхронных изменений за счет использования методов доступа, объявленных synchronized. В этом заключается еще одна причина, по которой вместо объявления полей public или protected следует применять методы для работы с ними: так вы сможете контролировать синхронизацию доступа к ним.
Если поле может измениться, оно никогда не должно считываться в тот момент, когда другой поток производит запись. Доступ к полям должен быть синхронизирован. Если бы один поток считывал значение поля, пока другой поток его устанавливает, то в результате могло бы получиться частично искаженное значение. Объявление synchronized гарантирует, что два (или более) потока не будут вмешиваться в работу друг друга. Тем не менее, на порядок выполнения операций не дается никаких гарантий; если сначала произойдет чтение, то оно закончится до того, как начнется запись, и наоборот. Если же вы хотите, чтобы все происходило в строго определенном порядке, работа потоков должна координироваться способом, зависящим от конкретного приложения.
Методы класса также могут синхронизироваться с использованием блокировки на уровне класса. Два потока не могут одновременно выполнять синхронизированные статические методы одного класса. Блокировка статического метода на уровне класса не отражается на объектах последнего — вы можете вызвать синхронизированный метод для объекта, пока другой поток заблокировал весь класс в синхронизированном статическом методе. В последнем случае блокируются только синхронизированные статические методы.
Если синхронизированный метод переопределяется в расширенном классе, то новый метод не обязан быть синхронизированным. Метод суперкласса при этом остается синхронизированным, так что несинхронность метода в расширенном классе не отменяет его синхронизированного поведения в суперклассе. Если в несинхронизированном методе используется конструкция super.method() для обращения к методу суперкласса, то объект блокируется на время вызова до выхода из метода суперкласса.
Дата добавления: 2015-02-16; просмотров: 654;