Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Multithreading in java past and actual

460 views

Published on

In this talk I’d like to give you an overview of java.util.concurrent package and represent useful Java concurrency tools. I’ll cover the core functionality and the state-of-the-art API (Executors, Accumulators, StampedLock etc).

Simple examples in github (https://github.com/levik666/OverviewInJavaUtilConcurrent)

Published in: Software
  • Be the first to comment

  • Be the first to like this

Multithreading in java past and actual

  1. 1. Multithreading in Java past & actual. April 20, 2016
  2. 2. 2CONFIDENTIAL • Полуков Євген, Software Engineer у EPAM – разработчик с более 6 годами опыта в ИТ из них более 2 лет в EPAM. На данный момент занимаюсь разработкой e-commerce (Hybris). Обо Мне
  3. 3. 3CONFIDENTIAL Введение Организация данных и задач1 Параллелизация за кулисами2 Загрузка процессоров полезной работой3 Хорошие алгоритмы4 Не надо изобретать велосипед5
  4. 4. 4CONFIDENTIAL О чем будем говорить? MM and HMA1 Executors2 Atomics and Accumulators3 Locks4 Synchronizers5
  5. 5. 5CONFIDENTIAL История: Java Concurrency TimeLine
  6. 6. 6CONFIDENTIAL Thread : MM • Каждий поток имет свой thread stack. • Вся информация о методах и их вызовах сохраняется в thread stack. • Все локальные примитивы сохраняются thread stack.
  7. 7. 7CONFIDENTIAL Thread: MM and HMA
  8. 8. 8CONFIDENTIAL Thread: MM and HMA какие есть проблемы? •Visibility of Shared Objects •Race Conditions
  9. 9. 9CONFIDENTIAL Thread: Visibility of Shared Objects • Если у нас возникает работа с общими объектами без использования volatile или synchronization. • В данном случае нам помогает volatile решить данную проблему.
  10. 10. 10CONFIDENTIAL Thread: Race Conditions • Гонка потоков при неатомарных операциях. Если у нас возникает работа с общими объектами без использование synchronization. • В данном случае нам помогает synchronization решить данную проблему.
  11. 11. 11CONFIDENTIAL Thread State
  12. 12. 12CONFIDENTIAL Executors •Возможность выбирать реализацию создания потоков. (newCachedThreadPool, newSingleThreadExecutor, newFixedThreadPool, newSingleThreadScheduledExecutor) •Удобное название потоков (по умолчанию pool- N-thread-N или кастомный ThreadFactory) •Запускать batch (Runnable, Callable) •Остановка потоков (shutdown, shutdownNow)
  13. 13. 13CONFIDENTIAL Executors: ScheduledExecutorService •Запуск потоков по расписанию – schedule(Runnable command, long delay, TimeUnit unit) – scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
  14. 14. 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);
  15. 15. 15CONFIDENTIAL Accumulators • Инкрементируем счетчик в разных потоках. • Узнать статистику - сколько потоков имеют доступ к общему методу. public void run() { ... counter.incrementAndGet(); } public long getCount() { return counter.get(); } Что использовать для counter?
  16. 16. 16CONFIDENTIAL Accumulators
  17. 17. 17CONFIDENTIAL Accumulators: LongAdder • Защита от коллизий за счет структуры и алгоритма • @sun.misc.Contended class Cell • cells: PaddedAtomicLong[availableProcessors()] • hash: Thread.threadLocalHandonProbe • Простой API
  18. 18. 18CONFIDENTIAL Accumulators: LongAdder final LongAdder counter = new LongAdder(); public void run() { ... counter.increment(); } public long getCount() { return counter.sum(); }
  19. 19. 19CONFIDENTIAL Accumulators: LongAdder: Подводные камни • get(), reset(), sum() под нагрузкой просаживают производительность из - за обхода всех ячеек.
  20. 20. 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; } }
  21. 21. 21CONFIDENTIAL Accumulators
  22. 22. 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(); }
  23. 23. 23CONFIDENTIAL Locks •Блокировка на чтение, на запись •Чтение без блокировки •Конвертация (RW <->WR) •Простота использования •И чтобы быстро работало Чего бы хотелось
  24. 24. 24CONFIDENTIAL Locks: ReentrantReadWriteLock • Lock, блокировка на чтение, на запись • Рекурсивный захват • Пробная блокировка, таймауты прерываемость • Условия • Честная/Нечестная
  25. 25. 25CONFIDENTIAL Locks: ReentrantReadWriteLock • AbstractQueuedSynchronizer – Атомарное состояние: volatile int state – Очередь ожидания с атомарными обновлениями • ThreadLocal<HoldCounter> • Инкапсуляция полная Что внутри
  26. 26. 26CONFIDENTIAL Locks
  27. 27. 27CONFIDENTIAL Locks: StampedLock • Lock, блокировка на чтение, на запись • Оптимистическое чтение • Конвертация (RW <->WR)
  28. 28. 28CONFIDENTIAL Locks: StampedLock class Point { private double x, y; private final StampedLock sl = new StampedLock();
  29. 29. 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); } }
  30. 30. 30CONFIDENTIAL Locks: StampedLock double distanceFromOrigin() { // A read-only method long stamp = sl.readLock(); try { return Math.hypot(x, y); } finally { sl.unlockRead(stamp); } }
  31. 31. 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); }
  32. 32. 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); } }
  33. 33. 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);
  34. 34. 34CONFIDENTIAL Locks: StampedLock • Оптимистическое чтение • Если проверки неудачные, можно захватить блокировку • Конвертация (RW <->WR) • native U.loadFance(), U.getLongVolatail();
  35. 35. 35CONFIDENTIAL Synchronizers • CountDownLatch • CyclicBarrier • Semaphore • Exchanger
  36. 36. 36CONFIDENTIAL Synchronizers : CountDownLatch • Позволяет одному или нескольким потокам ожидать до тех пор, пока не завершится определенное количество операций, выполняющих в других потоках. • Может использоваться раз.
  37. 37. 37CONFIDENTIAL Synchronizers : CountDownLatch • CountDownLatch(int count) • void await() • boolean await(long timeout, TimeUnit unit) • void countDown()
  38. 38. 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 } }
  39. 39. 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"); }
  40. 40. 40CONFIDENTIAL Synchronizers : CyclicBarrier • Очень похож на CountDownLatch но при достижение барьера его можно переиспользовать опять. • Возможность выполнить дополнительную логику до достижения барьера.
  41. 41. 41CONFIDENTIAL Synchronizers : CyclicBarrier • CyclicBarrier(int parties) • CyclicBarrier(int parties, Runnable barrierAction) • int await() • int await(long timeout, TimeUnit unit) • void reset()
  42. 42. 42CONFIDENTIAL Synchronizers : Exchanger • Как видно из названия, основное предназначение данного класса — это обмен объектами между двумя потоками. • При этом, также поддерживаются null значения, что позволяет использовать данный класс для передачи только одного объекта или же просто как синхронизатор двух потоков. • Первый поток, который вызывает метод exchange(...) заблокируется до тех пор, пока тот же метод не вызовет второй поток.
  43. 43. 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); } } }
  44. 44. 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(); }
  45. 45. 45CONFIDENTIAL Synchronizers : Semaphore • Используются для ограничения количества потоков при работе с аппаратными ресурсами или файловой системой. Доступ к общему ресурсу управляется с помощью счетчика (permits).
  46. 46. 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)
  47. 47. 47CONFIDENTIAL Synchronizers : Резюме • CountDownLatch - Делает одноразовую защелку, которую нельзя обнулить • CyclicBarrier - Барьер, который сбрасывается, когда он достигнет нуля, можна переиспользовать, плюс выполнять логику, когда барьер достигнут. • Exchanger - Предзназначен для обмена объектами между двумя потоками
  48. 48. 48CONFIDENTIAL Synchronizers : Резюме • Semaphore - Предназначен для ограничение количества роботы потоков в системе. Узким местом при использовании семафоров является заданное количества разрешений, т.к. зачастую это число приходится подбирать в зависимости от мощности «железа».
  49. 49. 49CONFIDENTIAL Конец 
  50. 50. 50CONFIDENTIAL Полезные ссылки и книжки • Java Concurrency in Practice 1st Edition • https://habrahabr.ru/company/luxoft/blog/157273/ • Effective Java (2nd Edition) 2nd Edition • The Art of Multiprocessor Programming, Revised Reprint 1st Edition • http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest • http://openjdk.java.net/jeps/188 • http://psy-lob-saw.blogspot.com/

×