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

ЖАНРЫ

Философия Java3

Эккель Брюс

Шрифт:

Fi 1 eChannel.MapMode.READ_0NLY, 0. fc.sizeO) .asIntBufferO; while(ib. hasRemainingO)

ib.getO; fc. closeO;

}

}.

new Tester("Stream Read/Write") {

public void testO throws IOException {

RandomAccessFile raf = new RandomAccessFile(

new FileC'temp.tmp"), "rw"); raf.writelnt(l);

for(int i = 0; i < numOfUbufflnts; i++) { raf.seek(raf.length - 4); raf,writelnt(raf.readlnt);

}

raf.closeO;

}

}.

new Tester("Mapped Read/Write") {

public void testO throws IOException {

FileChannel fc = new RandomAccessFile(

new FileC'temp.tmp"). "rw").getChannelО; IntBuffer ib e fc.map(

FileChannel.MapMode.READ_WRITE. 0. fc.sizeO) .asIntBufferO; ib.put(O);

for(int i = 1; i < numOfUbufflnts; i++)

ib.put(ib.get(i - 1)); fc.closeO;

}

}

}:

public static void main(String[] args) { for(Tester test ; tests) test.runTestO;

}

} /* Output; Stream Write; 0.56 Mapped Write; 0.12 Stream Read; 0.80

Mapped Read: 0.07 продолжение &

Stream Read/Write 5.32 Mapped Read/Write 0.02 */// ~

Как

уже было видно из предыдущих примеров книги, runTest — не что иное как метод шаблона, предоставляющий тестовую инфраструктуру для различных реализаций метода test, определенного в безымянных внутренних подклассах. Каждый из этих подклассов выполняет свой вид теста, таким образом, методы test также являются прототипами для выполнения различных действий, связанных с вводом/выводом.

Хотя кажется, что для отображаемой записи следует использовать поток FileOutputStream, на самом деле любые операции отображаемого вывода должны проходить через класс RandomAccessFile так же, как выполняется чтение/запись в рассмотренном примере.

Отметьте, что в методах test также учитывается инициализация различных объектов для работы с вводом/выводом, и, несмотря на то что настройка отображаемых файлов может быть затратной, общее преимущество по сравнению с потоковым вводом/выводом все равно получается весьма значительным.

Блокировка файлов

Блокировка файлов позволяет синхронизировать доступ к файлу как к совместно используемому ресурсу. Впрочем, потоки, претендующие на один и тот же файл, могут принадлежать различным виртуальным машинам JVM, или один поток может быть Java-потоком, а другой представлять собой обычный поток операционной системы. Блокированные файлы видны другим процессам операционной системы, поскольку механизм блокировки Java напрямую связан со средствами операционной системы. Вот простой пример блокировки файла:

//: io/Fi1eLocking.java import java.nio.channels.*; import java.util.concurrent.*; import java.io.*;

public class FileLocking {

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

FileOutputStream fos= new FileOutputStreamCfile txt");

FileLock fl = fos.getChannel О .tryLockO.

if(fl != null) {

System.out.println("Файл заблокирован"); Ti meUnit.MILLISECONDS.sieep(100); fl .releaseO;

System ои^ргШ1п("Блокировка снята"),

}

fos.closeO;

}

} /* Output; Файл заблокирован Блокировка снята *///:-

Блокировать файл целиком позволяет объект FileLock, который вы получаете, вызывая метод tryLock или lock класса FileChannel. (Сетевые каналы Socket-Channel, DatagramChannel и ServerSocketChannel не нуждаются в блокировании,

так как они доступны в пределах одного процесса. Вряд ли сокет будет использоваться двумя процессами совместно.) Метод tryLock не приостанавливает программу. Он пытается овладеть объектом блокировки, но если ему это не удается (если другой процесс уже владеет этим объектом или файл не является разделяемым), то он просто возвращает управление. Метод lockQ ждет до тех пор, пока не удастся получить объект блокировки, или поток, в котором этот метод был вызван, не будет прерван, или же пока не будет закрыт канал, для которого был вызван метод lock. Блокировка снимается методом FileChannel. release.

Также можно заблокировать часть файла вызовом

tryLockdong position, long size, boolean shared) или

lockdong position, long size, boolean shared)

Блокируется участок файла размером size от позиции position. Третий аргумент указывает, будет ли блокировка совместной.

Методы без аргументов приспосабливаются к изменению размеров файла, в то время как методы для блокировки участков не адаптируются к новому размеру файла. Если блокировка была наложена на область от позиции position до position + size, а затем файл увеличился и стал больше размера position + size, то часть файла за пределами position + size не блокируется. Методы без аргументов блокируют файл целиком, даже если он растет.

Поддержка блокировок с эксклюзивным или разделяемым доступом должна быть встроена в операционную систему. Если операционная система не поддерживает разделяемые блокировки и был сделан запрос на получение такой блокировки, используется эксклюзивный доступ. Тип блокировки (разделяемая или эксклюзивная) можно узнать при помощи метода FileLock.isShared.

Блокирование части отображаемого файла

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

В следующем примере каждый их двух потоков блокирует свою собственную часть файла:

//: io/LockingMappedFiles.java

// Блокирование части отображаемого файла

// {RunByHand}

import java.nio *,

import java nio channels *,

import java io *, продолжение &

public class LockingMappedFiles {

static final int LENGTH = Ox8FFFFFF; // 128 MB static FileChannel fc;

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

new RandomAccessFileC'test.dat", "rw").getChannel0; MappedByteBuffer out =

fc.map(Fi1eChannel.MapMode.READ_WRITE, 0. LENGTH); for(int i = 0; i < LENGTH; i++)

out.put((byte)'x'); new LockAndModify(out. 0, 0 + LENGTH/3); new LockAndModify(out, LENGTH/2, LENGTH/2 + LENGTH/4);

}

private static class LockAndModify extends Thread { private ByteBuffer buff; private int start, end;

LockAndModify(ByteBuffer mbb. int start, int end) { this.start = start; this.end = end; mbb.limit(end); mbb.position(start); buff = mbb.sliceO; startO;

Поделиться с друзьями: