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

java.util.concurrent Executor Framework (9)

Вот некоторые методы класса Executors:

static

callable( Runnable task )

Возвращает Callable-объект, который после

Callable<Object>

 

выполнения данной задачи возвращает null.

static <T>

callable( Runnable task, T

Возвращает Callable-объект, который после

Callable<T>

result )

выполнения данной задачи возвращает result

static ThreadFactory

defaultThreadFactory( )

Возвращает фабрику потоков, по умолчанию

 

 

используемую виртуальной машиной для создания

 

 

новых потоков.

static ExecutorService

newCachedThreadPool( )

Создает пул потоков, в котором новые потоки

 

 

создаются при необходимости, а ранее созданные

 

 

потоки используются, когда они свободны.

static ExecutorService

newCachedThreadPool( T

Создает пул потоков, в котором новые потоки

 

hreadFactory

создаются при необходимости с использованием

 

threadFactory )

указанной фабрики, а ранее созданные потоки

 

 

используются, когда они свободны.

static ExecutorService

newFixedThreadPool( int

Создает пул потоков фиксированного размера.

 

nThreads )

 

java.util.concurrent Executor Framework (10)

static ExecutorService

newFixedThreadPool( int

Создает пул потоков фиксированного

 

nThreads, ThreadFactory

размера с использованием заданной

 

threadFactory )

фабрики потоков.

static

newScheduledThreadPool( int

Создает пул потоков, реализующих

ScheduledExecutorService

corePoolSize )

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

static

newScheduledThreadPool( int

Создает пул потоков, реализующих

ScheduledExecutorService

corePoolSize, ThreadFactory

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

 

threadFactory )

использованием заданной фабрики потоков.

static ExecutorService

newSingleThreadExecutor( )

Создает исполнителя, который использует

 

 

единственный рабочий поток.

static ExecutorService

newSingleThreadExecutor( Thr

Создает исполнителя, который использует

 

eadFactory threadFactory )

единственный рабочий поток, создаваемый

 

 

с использованием заданной фабрики

 

 

потоков.

java.util.concurrent Executor Framework (11)

static

newSingleThreadScheduledExec

Создает исполнителя, который

ScheduledExecutorService

utor( )

использует единственный рабочий

 

 

поток для управляемого запуска задач.

static

newSingleThreadScheduledExec

Создает однопоточного исполнителя для

ScheduledExecutorService

utor( ThreadFactory

управляемого запуска задач с

 

threadFactory )

использованием заданной фабрики

 

 

потоков.

static ThreadFactory

privilegedThreadFactory( )

Возвращает фабрику потоков, у которых

 

 

есть те же самые полномочия, как у

 

 

текущего потока.

static ExecutorService

unconfigurableExecutorService(

Возвращает объект, который делегирует

 

ExecutorService executor )

данному исполнителю только методы

 

 

данного ExecutorService. Не могут быть

 

 

вызваны никакие другие методы.

static

unconfigurableScheduledExecuto Возвращает объект, который делегирует

ScheduledExecutorService

rService( ScheduledExecutorServ данному исполнителю только методы

 

ice executor )

данного ScheduledExecutorService. Не

 

 

могут быть вызваны никакие другие

 

 

методы.

java.util.concurrent

Расширение фреймворка Executor: ForkJoinPool

Это расширение разработано специально для упрощения распараллеливания рекурсивных задач.

Краткое описание используемых типов:

ForkJoinTask – это абстрактный класс, который является легковесным аналогом потока (Thread). Благодаря методам, реализованным в классе ForkJoinPool, можно в небольшом

количестве потоков выполнить существенно большее число задач. Это достигается путём так называемого work-stealing'а, когда поток спящей задачи на самом деле не спит, а выполняет другие задачи. У класса ForkJoinTask есть много интересных методов (аналогичных методам invoke* и submit), здесь рассмотрим только два:

fork(), который производит асинхронный запуск задачи

join(), который дожидается выполнения задачи и возвращает результат её выполнения.

Сам по себе класс ForkJoinTask практически не используется, потому что для подавляющего большинства задач уже есть готовые более конкретные реализации:

RecursiveAction, являющийся аналогом Runnable-объектов (на случай, если никакого значения возвращать не нужно, а нужно лишь выполнить некоторое действие), и

RecursiveTask, являющийся аналогом Callable-объектов.

ForkJoinPool – в этом классе как раз и реализована достаточно хитрая логика по распределению нагрузки между реальными потоками. Снаружи он выглядит практически как

самый обычный пул потоков, и особенностей в его использовании по сравнению с базовым ExecutorService нет (он наследует от класса AbstractExecutorService, реализующего этот

интерфейс). Приводить детальный обзор методов класса не будем, вместо этого рассмотрим пример.

java.util.concurrent

Расширение фреймворка Executor: ForkJoinPool. Пример (1)

// существо примера – рекурсивный обход дерева. Здесь пока определяется само дерево interface Node {

Collection<Node> getChildren( ); long getValue( );

}

class MyTree implements Node {

private Collection<Node> childrens = new ArrayList<Node>( );// коллекция дочерних узлов

private long value = 0;

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

public MyTree( long value ) {

// конструктор

this.value = value;

 

}

 

public Collection<Node> getChildren( ) {

// возврат корней поддеревьев

return childrens;

 

}

 

public long getValue( ) {

 

return value;

 

}

 

public void add( MyTree newNode ) {

// добавление корня нового поддерева

childrens.add( newNode );

 

}

 

}

java.util.concurrent

Расширение фреймворка Executor: ForkJoinPool. Пример (2)

// это класс, обеспечивающий многопоточный рекурсивный обход дерева class ValueSumCounter extends RecursiveTask<Long> {

private final Node node;

public ValueSumCounter( Node node ) { // конструктор this.node = node;

}

 

@Override

 

protected Long compute( ) {

// основной метод класса RecursiveTask

long sum = node.getValue( );

// для накопления результата

List<ValueSumCounter> subTasks = new LinkedList<>( ); // коллекция (список) подзадач for( Node child : node.getChildren( ) ) { // обход всех поддеревьев

ValueSumCounter task = new ValueSumCounter( child );// для каждого – своя подзадача task.fork( ); // которую запустим асинхронно

subTasks.add( task ); // и добавим в список для ожидания

}

for( ValueSumCounter task : subTasks ) { // переберем все подзадачи sum += task.join( ); // дождёмся выполнения подзадачи и прибавим ее результат

}

return sum; // вернем собственный результат

}

}

java.util.concurrent

Расширение фреймворка Executor: ForkJoinPool. Пример (3)

public class Main {

public static void main( String[ ] args ) {

 

 

 

1

 

 

 

MyTree root = new MyTree( 1 );

// создадим корень

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MyTree tmp = new MyTree( 2 );

// создадим поддерево

 

 

 

 

 

 

 

 

 

 

2

 

 

 

3

root.add( tmp ); // добавим его

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

root.add( new MyTree( 3 ) );

// добавим второе поддерево

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

tmp.add( new MyTree( 4 ) );

// добавим узлы

4

 

 

 

5

 

 

 

tmp.add( new MyTree( 5 ) );

// в первое поддерево

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// выполним обход всего дерева с использованием рекурсивной задачи: long result = new ForkJoinPool( ).invoke( new ValueSumCounter( root ) ); System.out.println( "Результат обхода: " + result );

}

}

Результат обхода: 15

Реализовывать обход дерева таким образом существенно удобнее и интуитивно- понятнее, чем было бы с использованием интерфейса Future<T> и прямым

программированием создания потоков.

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

java.util.concurrent Еще одно расширение

фреймворка Executor:

Класс ThreadPoolExecutor

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

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

Настраивается очередь задач, ожидающих выполнения

Обработчики, которые вызываются перед запуском или после завершения отдельных задач

Для выполнения всевозможных настроек используются внутренние классы:

ThreadPoolExecutor.AbortPolicy

ThreadPoolExecutor.CallerRunsPolicy

ThreadPoolExecutor.DiscardOldestPolicy

ThreadPoolExecutor.DiscardPolicy

java.util.concurrent.locks

Блокировки

До версии Java 1.5 мониторы и методы wait, notify, notifyAll были единственным доступным механизмом блокировок. Начиная с этой версии

появился новый механизм - блокировки, реализованные в виде набора классов и интерфейсов пакета java.util.concurrent.locks.

В отличие от мониторов они не обладают специфичным синтаксисом и не встроены в язык. Их использование осуществляется аналогично любым другим объектам Java. Но они обеспечивают несравненно большую гибкость в отличие от старых методов синхронизации.

При этом средства пакета java.util.concurrent.locks обеспечивают ту же семантику операций с памятью, что и мониторы.

Базовые операции с блокировками описывает интерфейс java.util.concurrent.locks.Lock. В отличие от мониторов функциональность

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

java.util.concurrent.locks Блокировки (1)

Типичная схема использования нового механизма блокировок выглядит так:

lockObject.lock(); try {

//cинхронизируемые действия

}finally {

lockObject.unlock();

}

где lockObject – это объект класса, реализующего интерфейс java.util.concurrent.locks.Lock.

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