Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
36
Добавлен:
27.03.2015
Размер:
639.49 Кб
Скачать

java.util.concurrent

Синхронизаторы. Семафоры (1)

К синхронизаторам можно отнести различного рода структуры, которые отвечают за координацию работы потоков. Некоторые такие структуры реализованы в пакете java.util.concurrency:

Семафоры

Барьеры

Обменники

Защелки

Считающим семафором называют целочисленную переменную, выполняющую те же функции, что и флаг блокировки. Однако в отличие от последнего она может принимать кроме 0 и 1 ( true/false) и другие целые положительные значения.

Семафоры используются для ограничения числа потоков, которые используют некий ресурс. Максимально возможное значение семафора, понимаемое как количество потоков, которые одновременно могут получить доступ к ресурсу, задается аргументом конструктора. Вторым (необязательным) аргументом может быть булево значение, определяющее "справедливость" захвата ресурса ожидающими потоками. При реализации справедливой политики ресурс будет отдан тому потоку, который первым попытался его захватить. За справедливость приходится платить довольно большими временными затратами, поэтому обычно реализуется несправедливый вариант.

java.util.concurrent

Синхронизаторы. Семафоры (2)

Основные методы класса java.util.concurrent.Semaphore:

void

acquire( )

Получить доступ к ресурсу. Поток блокируется, пока

 

 

не доступ не будет получен или пока его не прервут.

void

acquire( int permits )

Получить permits доступов к ресурсу. Поток

 

 

блокируется, пока не доступ не будет получен или

 

 

пока его не прервут.

void

acquireUninterruptibly()

Получить доступ к ресурсу с запретом прерывания.

void

acquireUninterruptibly( i

Получить permits доступов к ресурсу с запретом

 

nt permits )

прерывания.

int

availablePermits( )

Возвращает количество свободных доступов

int

drainPermits( )

Получить все свободные доступы

protected

getQueuedThreads( )

Возвращает коллекцию потоков, ожидающих

Collection<Thread>

 

получения доступа

int

getQueueLength( )

Возвращает количество потоков, ожидающих

 

 

получения доступа

boolean

hasQueuedThreads( )

Возвращает true, если есть хотя бы один ожидающий

 

 

поток

java.util.concurrent

Синхронизаторы. Семафоры (3)

boolean

isFair( )

Возвращает true, если для семафора установлена

 

 

справедливая политика

protected

reducePermits( int reduction )

Уменьшить количество доступов на указанную величину

void

 

 

void

release( )

Освободить один доступ

void

release( int permits )

Освободить указанное количество доступов

boolean

tryAcquire( )

Попытаться получить один доступ. В случае успеха

 

 

возвращается true.

boolean

tryAcquire( int permits )

Попытаться получить указанное количество доступов. В

 

 

случае успеха возвращается true.

boolean

tryAcquire( int permits, long

Попытаться получить указанное количество доступов в

 

timeout, TimeUnit unit )

течение заданного интервала времени. В случае успеха (и

 

 

если поток не был прерван) возвращается true.

boolean

tryAcquire( long timeout,

Попытаться получить один доступ в течение заданного

 

TimeUnit unit )

интервала времени. В случае успеха (и если поток не был

 

 

прерван) возвращается true.

java.util.concurrent

Синхронизаторы. Семафоры (4)

Задача "писатель-читатель", в которой для передачи данных используется пул буферов: interface Buffer {

void markAsUsed( ); boolean markedAsUsed( );

}

private final Semaphore buffers = new Semaphore( MAX_BUFFERS, true );

public Buffer getBuffer() throws InterruptedException { buffers.acquire();

Buffer buffer = getNextAvailableBuffer(); buffer.markAsUsed( );

return buffer;

}

public void retBuffer(Buffer buf) {

if (buf.markedAsUsed( ) == false) buffers.release( );

putBufferToQueue( buf );

}

java.util.concurrent

Синхронизаторы. Барьеры (1)

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

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

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

В пакете java.util.concurrent для реализации барьерной синхронизации используется класс CyclicBarrier. Конструкторы этого класса получают

количество потоков, которые должны достичь точки синхронизации и, опционально, экземпляр интерфейса Runnable, который должен быть

исполнен в момент достижения этой точки всеми потоками:

CyclicBarrier( int parties );

CyclicBarrier( int parties, Runnable barrierAction );

java.util.concurrent

Синхронизаторы. Барьеры (2)

Методы класса java.util.concurrent.CyclicBarrier:

int

await( )

Ожидание, пока заданное в конструкторе количество потоков

 

 

выполнит вызов этого метода.

int

await( long timeout,

Ожидание, пока заданное в конструкторе количество потоков

 

TimeUnit unit )

выполнит вызов этого метода или пока не закончится заданный

 

 

тайм-аут.

int

getNumberWaiting( )

Возвращает количество ожидающих потоков.

int

getParties( )

Возвращает количество потоков, требуемых для преодоления

 

 

этого барьера (установленное при создании экземпляра).

boolean

isBroken( )

Возвращает true, если хотя бы один поток прерван или ушел из

 

 

ожидания по тайм-ауту.

void

reset( )

Сброс барьера в исходное состояние.

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

java.util.concurrent Синхронизаторы.

Барьеры (3)

В этой программе параллельно вычисляются суммы элементов строк матрицы:

import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier;

public class Main {

private static int matrix[ ][ ] =

 

{

};

// инициализация или чтение матрицы

private static int results[ ];

 

static Boolean flag = false;

 

private static class Summator extends Thread {

int row;

 

// индекс строки для экземпляра сумматора

CyclicBarrier barrier;

// барьерный синхронизатор

Summator( CyclicBarrier barrier, int row ) { // конструктор сумматора this.barrier = barrier;

this.row = row;

}

java.util.concurrent

Синхронизаторы. Барьеры (4)

public void run( ) {

// метод потока

int columns = matrix[ row ].length;

 

int sum = 0;

 

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

// собственно суммирование

sum += matrix[ row ][ i ];

 

}

results[ row ] = sum;

System.out.println("Сумма элементов строки " + row + " равна: " + sum); try { // ожидание всех остальных

barrier.await( );

}catch ( InterruptedException ex ) { ex.printStackTrace( );

}catch ( BrokenBarrierException ex ) {

ex.printStackTrace( );

}

}

}

java.util.concurrent

Синхронизаторы. Барьеры (5)

public static void main( String args[ ] ) {

 

// здесь объявления

 

final int rows = matrix.length;

 

results = new int[ rows ];

 

Runnable merger = new Runnable( ) {

// внутренний класс

public void run() {

// сложение сумм по строкам

int sum = 0;

 

for ( int i = 0; i < rows; i++ )

 

sum += results[ i ];

 

synchronized( flag ) {

// извещение основного потока

flag.notifyAll( );

 

flag = true;

 

}

System.out.println("Сумма элементов матрицы равна: " + sum);

}

};

java.util.concurrent Синхронизаторы.

Барьеры (6)

CyclicBarrier barrier = new CyclicBarrier( rows, merger ); for ( int i = 0; i < rows; i++ ) { // запуск всех сумматоров

new Summator( barrier, i ).start( );

}

 

System.out.println( "Ожидание..." );

 

Сумма элементов строки 1 равна: 4 (9)

synchronized( flag ) {

while( !flag ){

Сумма элементов строки 2 равна: 9 (10)

try {

Сумма элементов строки 0 равна: 102 (8)

Сумма элементов строки 4 равна: 25 (12)

flag.wait( );

Ожидание (1)

} catch( InterruptedException e ) {

Сумма элементов строки 3 равна: 16 (11)

return;

Сумма элементов строки 5 равна: 612 (13)

}

Сумма элементов матрицы равна: 768 (13)

}

Вычисления закончены (1)

}

System.out.println( "Вычисления закончены" );

}

}

В скобках показаны идентификаторы потоков.

Соседние файлы в папке Презентации по Java