Last active
August 29, 2015 13:58
-
-
Save iaveryanov/9949603 to your computer and use it in GitHub Desktop.
CAS and idling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package ru.inlinetelecom.vn2.util; | |
| import java.util.concurrent.CountDownLatch; | |
| import java.util.concurrent.ExecutorService; | |
| import java.util.concurrent.Executors; | |
| import java.util.concurrent.atomic.AtomicInteger; | |
| import java.util.concurrent.atomic.AtomicLong; | |
| /** | |
| * вариант с uncontended lock (getAvailableProcessors >= worker_count | |
| */ | |
| public class AtomicDecUntilZeroMain { | |
| // счетчик холостого хода | |
| private static AtomicLong idlingCounter = new AtomicLong(0); | |
| /** | |
| * 1) вызывается из многих потоков | |
| * 2) не должно быть меньше 0 | |
| * 3) если уже 0 и вызывают этот метод, то должно оставаться 0 | |
| * | |
| * @param counter | |
| * @return 0 or value after decrement | |
| */ | |
| private static int decUntilZero(AtomicInteger counter) { | |
| while (true) { | |
| int current = counter.get(); | |
| if (current == 0) { | |
| return current; | |
| } | |
| int next = current - 1; | |
| if (counter.compareAndSet(current, next)) { | |
| return next; | |
| } | |
| idlingCounter.incrementAndGet(); | |
| } | |
| } | |
| public static void main(String[] args) throws InterruptedException { | |
| final int initialValue = 400000000; | |
| final int countOfThreads = 4; // всего потоков | |
| final int countOfDecPerThread = initialValue/countOfThreads; // количество декрементов на один поток | |
| final AtomicInteger counter = new AtomicInteger(initialValue); | |
| ExecutorService executor = Executors.newFixedThreadPool(countOfThreads); | |
| long startedAt = System.currentTimeMillis(); | |
| final CountDownLatch latch = new CountDownLatch(countOfThreads); | |
| for (int i = 0; i < countOfThreads; i++) { | |
| executor.execute(new Runnable() { | |
| @Override | |
| public void run() { | |
| for (int i = 0; i < countOfDecPerThread; i++) { | |
| decUntilZero(counter); | |
| } | |
| latch.countDown(); | |
| // System.out.println("task in progress..." + (latch.getCount())); | |
| } | |
| }); | |
| } | |
| System.out.println("всех ждёмс, однако..."); | |
| latch.await(); | |
| long elapsed = System.currentTimeMillis() - startedAt; | |
| executor.shutdown(); // за ненадобностью более! | |
| System.out.println("Ну наконец-ТА дождалИСА!!! Урра товариСЧи, уРРа!"); | |
| System.out.println("================================================"); | |
| int now = counter.get(); | |
| System.out.println("== INPUT DATA"); | |
| System.out.println(String.format("%s: %d", "initial ", initialValue)); | |
| System.out.println(String.format("%s: %d", "threads ", countOfThreads)); | |
| System.out.println(String.format("%s: %d", "dec per threads ", countOfDecPerThread)); | |
| System.out.println("== RESULTS"); | |
| System.out.println(String.format("%s: %d", "еще осталось ", now)); | |
| System.out.println(String.format("%s: %d", "раз выполнилось ", (initialValue - now))); | |
| System.out.println(String.format("%s: %d", "холостых ходов ", idlingCounter.get())); | |
| System.out.println(String.format("%s: %s", "elapsed, millis ", elapsed)); | |
| } | |
| } |
Author
Время увеличилось в 2 раза вот почему.
Кол-во промахов стало в 3 раза больше.
Кол-во одновременно работающих потоков (так как 12 ядер) стало в 3 раза больше, а, следовательно, конфликтов стало больше. Вероятность конфликта растет с количеством одновременно работающих потоков. Операция cmpxchg блокирует шину данных при чтении из памяти.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Интрересно, почему время увеличилось в 2 раза?