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 раза?
Время увеличилось в 2 раза вот почему.
Кол-во промахов стало в 3 раза больше.
Кол-во одновременно работающих потоков (так как 12 ядер) стало в 3 раза больше, а, следовательно, конфликтов стало больше. Вероятность конфликта растет с количеством одновременно работающих потоков. Операция cmpxchg блокирует шину данных при чтении из памяти.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Profile
java version "1.7.0_40"
Java(TM) SE Runtime Environment (build 1.7.0_40-b43)
Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode)
Linux 2.6.38-13-server #57 SMP Sun Feb 19 22:11:49 UTC 2012 x86_64 GNU/Linux
2 x Intel(R) Xeon(R) CPU E5645 @ 2.40GHz, т.е. 12 hardware cpu core или 24 потока
Results
Initial value - 400 000 000