multithreading in java past and actual

Post on 15-Apr-2017

397 Views

Category:

Software

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Multithreading in Java past & actual.

April 20, 2016

2CONFIDENTIAL

• Полуков Євген, Software Engineer у EPAM – разработчик с более 6 годами опыта в ИТ из них более 2 лет в EPAM. На данный момент занимаюсь разработкой e-commerce (Hybris).

Обо Мне

3CONFIDENTIAL

Введение

Организация данных и задач 1

Параллелизация за кулисами 2

Загрузка процессоров полезной работой3

Хорошие алгоритмы4

Не надо изобретать велосипед5

4CONFIDENTIAL

О чем будем говорить?

MM and HMA 1

Executors 2

Atomics and Accumulators3

Locks4

Synchronizers5

5CONFIDENTIAL

История: Java Concurrency TimeLine

     

6CONFIDENTIAL

Thread : MM

• Каждий поток имет свой thread stack.

• Вся информация о методах и их вызовах сохраняется в thread stack.

• Все локальные примитивы сохраняются thread stack.

7CONFIDENTIAL

Thread: MM and HMA

8CONFIDENTIAL

Thread: MM and HMA какие есть проблемы?

Visibility of Shared Objects Race Conditions

9CONFIDENTIAL

Thread: Visibility of Shared Objects

• Если у нас возникает работа с общими объектами без использования volatile или synchronization.

• В данном случае нам помогает volatile решить данную проблему.

10CONFIDENTIAL

Thread: Race Conditions

• Гонка потоков при неатомарных операциях. Если у нас возникает работа с общими объектами без использование synchronization.

• В данном случае нам помогает synchronization решить данную проблему.

11CONFIDENTIAL

Thread State

12CONFIDENTIAL

Executors

Возможность выбирать реализацию создания потоков. (newCachedThreadPool, newSingleThreadExecutor, newFixedThreadPool, newSingleThreadScheduledExecutor)

Удобное название потоков (по умолчанию pool-N-thread-N или кастомный ThreadFactory)

Запускать batch (Runnable, Callable)Остановка потоков (shutdown, shutdownNow)

13CONFIDENTIAL

Executors: ScheduledExecutorService

Запуск потоков по расписаниюschedule(Runnable command, long delay, TimeUnit unit)

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

14CONFIDENTIAL

Executors: ScheduledExecutorService

service =  Executors.newSingleThreadScheduledExecutor();если требуется отложить выполнение на 5 секунд

service.schedule(()-> { ... }, 5, TimeUnit.SECONDS);Если требуется назначить выполнение каждую секунду:

service.scheduleAtFixedRate(() -> { ... }, 0, 1, TimeUnit.SECONDS);

Eсли требуется назначить выполнение кода с промежутком 1 секунда между выполнениями:service.scheduleWithFixedDelay(()-> { ... }, 0, 1, TimeUnit.SECONDS);

15CONFIDENTIAL

Accumulators

Инкрементируем счетчик в разных потоках.

Узнать статистику - сколько потоков имеют доступ к общему методу.

public void run() {   ...   counter.incrementAndGet();}

public long getCount() {   return counter.get();}

Что использовать для counter?

16CONFIDENTIAL

Accumulators

17CONFIDENTIAL

Accumulators: LongAdder

Защита от коллизий за счет структуры и алгоритма

@sun.misc.Contended class Cellcells: PaddedAtomicLong[availableProcessors()]

hash: Thread.threadLocalHandonProbeПростой API

18CONFIDENTIAL

Accumulators: LongAdder

final LongAdder counter = new LongAdder();

public void run() {   ...   counter.increment();}

public long getCount() {   return counter.sum();}

19CONFIDENTIAL

Accumulators: LongAdder: Подводные камни

get(), reset(), sum() под нагрузкой просаживают производительность из - за обхода всех ячеек. 

20CONFIDENTIAL

Accumulators: Atomic Update

/*** Atomically adds the given value to the current value.** @param delta the value to add* @return the previous value*/public final int getAndAdd(int delta) {   for (;;) {       int current = get();       int next = current + delta;       if (compareAndSet(current, next))           return current;   }}

21CONFIDENTIAL

Accumulators

22CONFIDENTIAL

Accumulators: LongAccumulator

final LongAccumulator counter = new LongAccumulator(

(left, right) -> left * right, 2l );

//LongBinaryOperator//final LongAccumulator counter = new LongAccumulator(

Long::sum, 0l

);//final AtomicLong counter = new AtomicLong(0);

public void run() {   counter.accumulate(1);   //counter.updateAndGet(counter->counter+1);}

public long getCount() {   return counter.get();}

23CONFIDENTIAL

Locks

Блокировка на чтение, на записьЧтение без блокировкиКонвертация (RW <->WR)Простота использованияИ чтобы быстро работало

Чего бы хотелось

24CONFIDENTIAL

Locks: ReentrantReadWriteLock

Lock, блокировка на чтение, на запись

Рекурсивный захват Пробная блокировка, таймауты прерываемость

УсловияЧестная/Нечестная

25CONFIDENTIAL

Locks: ReentrantReadWriteLock

AbstractQueuedSynchronizerАтомарное состояние: volatile int stateОчередь ожидания с атомарными обновлениями

ThreadLocal<HoldCounter>Инкапсуляция полная

Что внутри

26CONFIDENTIAL

Locks

27CONFIDENTIAL

Locks: StampedLock

Lock, блокировка на чтение, на запись

Оптимистическое чтениеКонвертация (RW <->WR)

28CONFIDENTIAL

Locks: StampedLock

class Point {private double x, y;private final StampedLock sl = new

StampedLock();

29CONFIDENTIAL

Locks: StampedLock

void move(double deltaX, double deltaY) { // an exclusively locked method

  long stamp = sl.writeLock();  try {      x += deltaX;      y += deltaY;  } finally {      sl.unlockWrite(stamp);  }}

30CONFIDENTIAL

Locks: StampedLock

double distanceFromOrigin() { // A read-only method  long stamp = sl.readLock();  try {      return Math.hypot(x, y);  } finally {      sl.unlockRead(stamp);  }}

31CONFIDENTIAL

Locks: StampedLock

double distanceFromOrigin() { // A read-only method  long stamp = sl.tryOptimisticRead();  double currentX = x, currentY = y;  if (!sl.validate(stamp)) {      stamp = sl.readLock();      try {          currentX = x;   currentY = y;      } finally {          sl.unlockRead(stamp);      }  }  return Math.sqrt(currentX * currentX + currentY *

currentY);}

32CONFIDENTIAL

Locks: StampedLock

void moveIfAtOrigin(double newX, double newY) {  long stamp = sl.writeLock();  try {      if (x == 0.0 && y == 0.0) {          x = newX;          y = newY;      }  } finally {      sl.unlockWrite(stamp);  }}

33CONFIDENTIAL

Locks: StampedLock

long stamp = sl.readLock(); // Could instead start with optimistic, not read mode

  try {      while (x == 0.0 && y == 0.0) {          long ws = sl.tryConvertToWriteLock(stamp);          if (ws != 0L) {              stamp = ws;  x = newX;  y = newY;              break;          } else {              sl.unlockRead(stamp);              stamp = sl.writeLock();          }      }  } finally {      sl.unlock(stamp);

34CONFIDENTIAL

Locks: StampedLock

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

Конвертация (RW <->WR)native U.loadFance(), U.getLongVolatail();

35CONFIDENTIAL

Synchronizers

CountDownLatchCyclicBarrierSemaphoreExchanger

36CONFIDENTIAL

Synchronizers : CountDownLatch

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

Может использоваться раз.

37CONFIDENTIAL

Synchronizers : CountDownLatch

CountDownLatch(int count)void await()boolean await(long timeout, TimeUnit unit)void countDown()

38CONFIDENTIAL

Synchronizers : CountDownLatch

class Service implements Runnable {  private static final int EMULATE_TIME_TO_START = 1000;  private final String name;  private final CountDownLatch latch;

public void run() {      ...      sleep(EMULATE_TIME_TO_START);      Logger.getLogger(Service.class.getName()).log(

Level.INFO, name + " is Up");      latch.countDown(); //reduce count of CountDownLatch by 1

   }}

39CONFIDENTIAL

Synchronizers : CountDownLatch

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

  final CountDownLatch latch = new CountDownLatch(3);  final ExecutorService executorService =

Executors.newCachedThreadPool();

executorService.submit(new Service(CACHE, latch));  executorService.submit(new Service(ALERT, latch));  executorService.submit(new Service(GSM, latch));  latch.await();  //main thread is waiting on CountDownLatch to finish

Logger.getLogger(Service.class.getName()).log(Level.INFO, "All services are up,

Application is starting now");}

40CONFIDENTIAL

Synchronizers : CyclicBarrier

Очень похож на CountDownLatch но при достижение барьера его можно переиспользовать опять.

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

41CONFIDENTIAL

Synchronizers : CyclicBarrier

CyclicBarrier(int parties)CyclicBarrier(int parties, Runnable barrierAction)int await()int await(long timeout, TimeUnit unit)void reset()

42CONFIDENTIAL

Synchronizers : Exchanger

Как видно из названия, основное предназначение данного класса — это обмен объектами между двумя потоками.

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

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

43CONFIDENTIAL

Synchronizers : Exchanger

class SimpleChat implements Runnable {  public SimpleChat(Exchanger<String> exchanger, String message)

{      this.exchanger = exchanger;      this.message = message;  }  public void run() {      try {          Logger.getLogger(Service.class.getName()).log(Level.INFO,

getName() + " message: " + message);          message = exchanger.exchange(message);   // exchange messages

      } catch (Exception exe) {          Logger.getLogger(Service.class.getName()).log(Level.SEVERE,

exe);      }  }}

44CONFIDENTIAL

Synchronizers : Exchanger

public static void main(String[] args) {  final Exchanger<String> exchanger = new Exchanger<>();  final ExecutorService executorService =

Executors.newCachedThreadPool();

  executorService.submit(new SimpleChat(exchanger, "Неплохо

бы завтра в зал. Ну что идем?"));

  executorService.submit(new SimpleChat(exchanger, "Да настало

время жать!!!"));

  executorService.shutdown();}

45CONFIDENTIAL

Synchronizers : Semaphore

Используются для ограничения количества потоков при работе с аппаратными ресурсами или файловой системой. Доступ к общему ресурсу управляется с помощью счетчика (permits).

46CONFIDENTIAL

Synchronizers : Semaphore

Semaphore(int permits)void acquire(); void acquire(int permits)boolean tryAcquire(); boolean tryAcquire(long timeout, TimeUnit unit)void release(); void release(int permits)protected void reducePermits(int reduction)

47CONFIDENTIAL

Synchronizers : Резюме

CountDownLatch- Делает одноразовую защелку, которую

нельзя обнулитьCyclicBarrier

- Барьер, который сбрасывается, когда он достигнет нуля, можна переиспользовать, плюс выполнять логику, когда барьер достигнут.

Exchanger - Предзназначен для обмена объектами между двумя потоками

48CONFIDENTIAL

Synchronizers : Резюме

Semaphore- Предназначен для ограничение количества роботы потоков в системе. Узким местом при использовании семафоров является заданное количества разрешений, т.к. зачастую это число приходится подбирать в зависимости от мощности «железа».

49CONFIDENTIAL

Конец

50CONFIDENTIAL

Полезные ссылки и книжки

Java Concurrency in Practice 1st Editionhttps://habrahabr.ru/company/luxoft/blog/157273/Effective Java (2nd Edition) 2nd EditionThe Art of Multiprocessor Programming, Revised Reprint 1st Editionhttp://altair.cs.oswego.edu/mailman/listinfo/concurrency-interesthttp://openjdk.java.net/jeps/188http://psy-lob-saw.blogspot.com/

top related