1. Применимые сценарии для CAS и синхронизированных
1. Для ситуаций, когда конкуренция за ресурсами меньше, использование синхронизированной блокировки синхронизации для блокировки потоков и операций переключения пробуждения и переключения между ядрами пользовательского состояния является дополнительной тратой ресурсов ЦП; Хотя CAS реализуется на основе аппаратного обеспечения, не нужно входить в ядро, не нужно переключать потоки, а вероятность использования спина меньше, поэтому можно получить более высокую производительность.
2. В случае серьезной конкуренции за ресурсами вероятность спина CAS относительно высока, что тратит больше ресурсов процессора и менее эффективна, чем синхронизирована. Принимая класс AtomicInteger в java.util.concurrent.atomic Package В качестве примера, его метод GetAndIncrement () реализован следующим образом:
public final int getAndIncrement () {for (;;) {int current = get (); int next = current + 1; if (CompareAndset (current, Next)) возврат ток; }}Если метод сравнения (текущий, следующий) успешно выполнен, он будет возвращен напрямую; Если конкуренция потоков является жесткой, что приводит к методу сравнения (ток, следующий), который не может быть успешно выполнен, он будет зациклен и будет ждать до тех пор, пока срез, выделяемый ЦП, на потоку, не будет исчерпан, тем самым значительно снижает эффективность.
2. Сценарии использования ошибок CAS
открытый класс casdemo {private final int thread_num = 1000; Приватный окончательный финал int max_value = 20000000; Частный AtomicInteger casi = новый AtomicInteger (0); private int synci = 0; private String path = "/users/pingping/datacenter/books/linux/linux commons.txt"; public void casadd () бросает прерванное эктрипений {long begin = system.currenttimemillis (); Thread [] Threads = новый поток [thread_num]; for (int i = 0; i <think_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (casi.get () <max_value) {casi.getandinCrement ();}}}); Threads [i] .start (); } for (int j = 0; j <think_num; j ++) {threads [j] .join (); } System.out.println ("CAS затрат времени:" + (System.currentTimeMillis () - begin)); } public void syncAdd () throws urruptedException {long begin = System.currentTimeMillis (); Thread [] Threads = новый поток [thread_num]; for (int i = 0; i <think_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (synci <max_value) {synchronized ("synci") {++ synci;}}}}}}); Threads [i] .start (); } for (int j = 0; j <think_num; j ++) потоки [j] .join (); System.out.println ("Синхронизация затрат времени:" + (system.currenttimemillis () - begin)); }}Запуск на моем двухъядерном процессоре, результат заключается в следующем:
Можно видеть, что при разных потоках время, потраченное на использование расчета CAS, гораздо больше, чем у синхронизации. Причина - строка 15
14 while (casi.get () <max_value) {15 casi.getandincrement (); 16}Операция-очень трудоемкая операция. После того, как 15 строк будут выполнены, цикл будет немедленно введен, и выполнение будет продолжаться, что приведет к серьезным конфликтам потоков.
3. Улучшенные сценарии использования CAS
Чтобы решить вышеупомянутую проблему, необходимо только сделать время выполнения каждой петли дольше, то есть она может значительно уменьшить конфликты потоков. Изменить код следующим образом:
открытый класс casdemo {private final int thread_num = 1000; Приватный окончательный int max_value = 1000; Частный AtomicInteger casi = новый AtomicInteger (0); private int synci = 0; private String path = "/users/pingping/dataCenter/books/linux/linux commonces destistemed urpanation.txt"; public void casadd2 () бросает прерванную экзенцию {long begin = system.currenttimemillis (); Thread [] Threads = новый поток [thread_num]; для (int i = 0; i <think_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (casi.get () <max_value) {casi.getandincrement (); try (inputStream in = new FileInptream (new File)) {in (in.) e) {e.printstacktrace ();}}}}}); Threads [i] .start (); } for (int j = 0; j <think_num; j ++) потоки [j] .join (); System.out.println ("CAS случайные затраты Время:" + (System.currentTimeMillis () - begin)); } public void syncAdd2 () бросает прерывание {long begin = system.currenttimemillis (); Thread [] Threads = новый поток [thread_num]; for (int i = 0; i <thenk_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (synci <max_value) {synchronized ("synci") {++ synci;} try (inputstream in = new FileInputStream (new file (pather) {in (in) } catch (ioException e) {e.printstacktrace (); Threads [i] .start (); } for (int j = 0; j <think_num; j ++) потоки [j] .join (); System.out.println ("Синхронизация затрат времени:" + (system.currenttimemillis () - begin)); }}В цикле while добавляется операция по чтению содержимого файла, которая занимает около 40 мс, тем самым уменьшая конфликты потоков. Результаты теста следующие:
Можно видеть, что когда конфликты ресурсов относительно невелики, метод CAS и эффективность синхронизированной синхронизации аналогичны. Почему CAS не достигает более высокой производительности, чем синхронизированный?
JDK, используемый в тесте, составляет 1,7. Начиная с JDK1.6, было введено множество оптимизаций для реализации замков, таких как шиловало, устранение блокировки, легкая блокировка, предвзятая блокировка, адаптивное спиннинг и другие технологии, чтобы уменьшить накладные расходы на операцию блокировки. Принцип спин -блокировки похож на CAS Spin и даже более оптимизирован, чем CAS Spin. Для получения подробной информации, пожалуйста, обратитесь к углубленному механизму блокировки JVM 1-Synchronized.
4. Резюме
1. При использовании CAS, когда конфликты потоков являются серьезными, производительность программы будет значительно снижена; CAS подходит только для ситуаций, когда меньше ниточных конфликтов.
2. Синхронизированный был улучшен и оптимизирован после JDK1.6. Основная реализация синхронизированной в основном зависит от очереди без блокировки. Основная идея состоит в том, чтобы блокировать после спина, продолжать конкурировать за замки после переключения конкуренции, слегка жертвуя справедливостью, но получая высокую пропускную способность. Когда меньше потоковых конфликтов, аналогичная производительность может быть получена; Когда возникают серьезные конфликты ниток, производительность намного выше, чем у CAS.
Приведенное выше резюме Java -одновременного программирования - тщательно с использованием CAS является подробным объяснением редактора. Я надеюсь, что это может дать вам ссылку, и я надеюсь, что вы сможете поддержать Wulin.com больше.