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

java.util.concurrent

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

Обменник – это параметризованный класс Exchanger пакета java.util.concurrent, с помощью которого можно осуществлять передачу данных

между потоками, не заботясь о синхронизации (она реализуется внутренними средствами класса).

В двух потоках, которым нужно обменяться данными, вызывается метод exchange() экземпляра класса Exchanger, доступного каждому из них. В

качестве аргумента метода указывается значение (его тип должен быть приводим к параметру используемого экземпляра обменника), которое должно быть отдано другому потоку:

V exchange( V sendingValue )

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

Существует возможность указать продолжительность тайм-аута ожидания,

после истечения которого проснувшийся поток получит для обработки исключение TimeoutException:

V exchange( V sendingValue, long timeout, TimeUnit tUnit )

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

Вычислим параллельно суммы элементов строк матрицы с использованием обменников.

java.util.concurrent

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

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

import java.util.concurrent.Exchanger; import java.util.concurrent.TimeUnit;

import java.util.concurrent.TimeoutException;

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

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

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

Синхронизаторы. Барьеры и обменники (3)

public static void main( String args[ ] ) { // здесь объявления

final int rows = matrix.length; results = new int[ rows ];

final Exchanger<Integer> myExchanger = new Exchanger<Integer>( );

Runnable merger = new Runnable( ) {

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

public void run( ) {

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

int sum = 0;

 

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

 

sum += results[ i ];

 

try {

// обмен данными и синхронизация с основным потоком

myExchanger.exchange( Integer.valueOf( sum ) ); } catch( InterruptedException ex ) {

ex.printStackTrace( );

}

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

}

};

java.util.concurrent

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

CyclicBarrier barrier = new CyclicBarrier( rows, merger );

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

}

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

Integer result = myExchanger.exchange( 0 ); // получение результатов System.out.println( "Вычисления закончены. " + result );

}

}

Сумма элементов строки 0 равна: 15 (8) Сумма элементов строки 2 равна: 77 (10) Сумма элементов строки 4 равна: 100 (12) Ожидание... (1)

Сумма элементов строки 1 равна: 13 (9) Сумма элементов строки 3 равна: 48 (11) Сумма элементов строки 5 равна: 23 (13) Сумма элементов матрицы равна: 276 (13) Вычисления закончены.276 (1)

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

Защелка (1)

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

Класс CountDownLatch пакета java.util.concurrent является соответствующим средством синхронизации. Он работает по принципу таймера, только отсчеты вырабатываются программно, а не кварцевым генератором.

При создании экземпляра класса его внутренний счетчик инициализируется

начальным значением, передаваемым конструктору. Значение счетчика может быть уменьшено на 1 путем вызова метода countDown(). При вызове метода

await() каким-либо потоком, он переходит в состояние ожидания момента

достижения счетчиком значения 0. Есть перегруженный метод

await(long timeout, TimeUnit unit), позволяющий организовать ожидание не дольше, чем в течение заданного интервала. Есть также метод getCount(),

позволяющий получить текущее значение счетчика.

В отличие от класса CyclicBarrier экземпляры этого класса одноразовые.

На практике данный класс удобно использовать для координации момента начала и окончания определенного числа потоков:

можно сделать так, чтобы исполнение заданного числа потоков начиналось в один и тот же момент времени;

можно отследить момент окончания заданного числа потоков.

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

Защелка (2)

class Master { // ...

int threadsCount = … ; // определение количества потоков Worker void masterMain( ) throws InterruptedException {

CountDownLatch startLatch = new CountDownLatch( 1 ); CountDownLatch readyLatch = new CountDownLatch( threadsCount );

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

// создание и запуск потоков

new Thread( new Worker( startLatch, readyLatch ) ).start( );

doSomething( );

// делается что-то

startLatch.countDown( );

// фактический запуск

doSomethingYet( );

// делается что-то еще

readyLatch.await( ); // ожидание момента завершения всех потоков

}

// …

}

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

Защелка (3)

class Worker implements Runnable { private final CountDownLatch starting; private final CountDownLatch finishing;

Worker( CountDownLatch starting, CountDownLatch finishing ) { // конструктор this.starting = starting;

this.finishing = finishing;

}

 

public void run( ) {

 

try {

 

starting.await();

// ожидание разрешения работать

doWork();

// выполнение работы

finishing.countDown();

// отметка, что поток завершился

} catch ( InterruptedException ex ) {

}

return;

}

void doWork() { ... }

}

java.util.concurrent.atomic Классы с атомарными

операциями

Подпакет java.util.concurrent.atomic содержит несколько классов, предоставляющих атомарные операции:

AtomicBoolean

AtomicInteger

AtomicIntegerArray

AtomicIntegerFieldUpdater

AtomicLong

AtomicLongArray

AtomicLongFieldUpdater

AtomicMarkableReference

AtomicReference

AtomicReferenceArray

AtomicReferenceFieldUpdater

AtomicStampedReference

java.util.concurrent.atomic Основные методы атомарных классов (1)

 

У всех (кроме *Reference):

boolean

compareAndSet(

сравнить текущее значение с expect, если совпадают –

 

* expect, * update ) атомарно заменить текущее на update и вернуть true,

 

 

иначе – вернуть false

*

get()

вернуть текущее значение

*

getAndSet( *

атомарно заменить значение на newValue, вернуть

 

newValue)

предыдущее значение

void

lazySet( * newValue )

На процессорах x86 практически ничем не отличается

 

 

от просто set, но использовать можно, только тщательно

 

 

разобравшись в отличии от метода set

void

set( * newValue )

атомарно заменить значение на newValue

boolean weakCompareAndSet На процессорах x86 практически ничем не отличается ( * expect, * update ) от просто compareAndSet, но использовать можно,

только тщательно разобравшись в особенностях

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