1. Cenários aplicáveis para CAS e sincronizados
1. Para situações em que a concorrência de recursos é menor, o uso de bloqueio de sincronização sincronizado para bloqueio de roscas e operações de comutação e troca de despertar entre os kernels do estado-estado é um desperdício extra de recursos da CPU; Embora o CAS seja implementado com base no hardware, não precisa entrar no kernel, não precisa alterar os threads e a chance de operar o giro é menor, portanto, um desempenho mais alto pode ser obtido.
2. Em caso de concorrência séria de recursos, a probabilidade de giro CAS é relativamente alta, desperdiçando mais recursos da CPU e sendo menos eficiente do que o sincronizado. Tomando a classe AtomicInteger no pacote java.util.concurrent.atomic como exemplo, seu método getAndincrement () é implementado da seguinte forma:
public final int getAndIncrement () {for (;;) {int current = get (); int próximo = corrente + 1; if (comparaandndSet (atual, próximo)) retornar corrente; }}Se o método ComparaDSet (atual, a seguir) for executado com sucesso, ele será retornado diretamente; Se a concorrência do encadeamento for feroz, resultando no método ComparaDSet (atual, próximo) que não pode ser executado com sucesso, ele será loop e esperado até que a fatia de tempo alocada pela CPU ao encadeamento seja esgotada, reduzindo bastante a eficiência.
2. Cenários de uso de erro CAS
classe pública casdemo {private final int thread_num = 1000; Final privado int max_value = 20000000; Atomicinteger privado Casi = new AtomicInteger (0); private int synci = 0; Private String Path = "/Usuários/pingping/datacenter/books/linux/linux Commands.txt"; public void Casadd () lança interruptedException {long begin = System.currenttimemillis (); Thread [] threads = novo thread [thread_num]; para (int i = 0; i <thread_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (casi.get () <max_value) {casi.getAndincrement ();}}}); threads [i] .start (); } para (int j = 0; j <Thread_num; j ++) {threads [j] .Join (); } System.out.println ("Cas custa tempo:" + (System.currenttimemillis () - BEGIN)); } public void syncadd () lança interruptedException {long começo = system.currenttimemillis (); Thread [] threads = novo thread [thread_num]; para (int i = 0; i <Thread_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (synci <max_value) {synchronized ("synci") {++ synci;}}}}}); threads [i] .start (); } para (int j = 0; j <thread_num; j ++) threads [j] .Join (); System.out.println ("Sync custa tempo:" + (System.currenttimemillis () - BEGIN)); }}Correndo na minha CPU de núcleo duplo, o resultado é o seguinte:
Pode -se observar que, em diferentes encadeamentos, o tempo gasto usando o cálculo do CAS é muito mais do que o de sincronizado. O motivo é a linha 15
14 while (casi.get () <max_value) {15 casi.getAndIncrement (); 16}A operação é uma operação muito demorada. Após a execução de 15 linhas, o loop será inserido imediatamente e a execução continuará, resultando em conflitos graves de threads.
3. Cenários de uso aprimorados do CAS
Para resolver o problema acima, é necessário apenas tornar o tempo de execução de cada loop por mais tempo, ou seja, pode reduzir bastante os conflitos de roscas. Modifique o código da seguinte forma:
classe pública casdemo {private final int thread_num = 1000; Final privado int max_value = 1000; Atomicinteger privado Casi = new AtomicInteger (0); private int synci = 0; Private String Path = "/Usuários/Pingping/Datacenter/Books/Linux/Linux Comandos Comuns Comandos detalhados explicação.txt"; public void Casadd2 () lança interruptedException {long begin = System.currenttimemillis (); Thread [] threads = novo thread [thread_num]; para (int i = 0; i <Thread_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (casi.get () <max_value) {Casi.getAndincrement (); Try (inputStream em = new FileIrtStream (new File)) {; e) {E.PrintStackTrace (); threads [i] .start (); } para (int j = 0; j <thread_num; j ++) threads [j] .Join (); System.out.println ("Cas Random custa tempo:" + (System.currenttimemillis () - BEGIN)); } public void syncadd2 () lança interruptedException {long begin = system.currenttimemillis (); Thread [] threads = novo thread [thread_num]; para (int i = 0; i <Thread_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (synci <max_value) {synchronized ("synci") {++ synci;} try (inputStream em = newNputStream "(fileInpTream") {++ sínci; } catch (ioexception e) {e.printStackTrace (); threads [i] .start (); } para (int j = 0; j <thread_num; j ++) threads [j] .Join (); System.out.println ("Sync custa tempo:" + (System.currenttimemillis () - BEGIN)); }}No while loop, é adicionada uma operação para ler o conteúdo do arquivo, que leva cerca de 40ms, reduzindo assim os conflitos de threads. Os resultados dos testes são os seguintes:
Pode -se observar que, quando os conflitos de recursos são relativamente pequenos, o método CAS e a eficiência da sincronização sincronizada são semelhantes. Por que o CAS não atinge um desempenho mais alto do que o sincronizado?
O JDK usado no teste é 1.7. A partir do JDK1.6, muitas otimizações foram introduzidas na implementação de bloqueios, como bloqueio de bloqueio, eliminação de bloqueio, travamento leve, bloqueio tendencioso, fiação adaptativa e outras tecnologias para reduzir a sobrecarga da operação de bloqueio. O princípio do bloqueio de spin é semelhante ao spin CAS e é ainda mais otimizado que o giro CAS. Para detalhes, consulte o mecanismo de bloqueio JVM aprofundado 1-sincronizado.
4. Resumo
1. Ao usar o CAS, quando os conflitos de threads são graves, o desempenho do programa será bastante reduzido; O CAS é adequado apenas para situações em que há menos conflitos de threads.
2. O sincronizado foi melhorado e otimizado após o JDK1.6. A implementação subjacente de sincronizada baseia-se principalmente na fila do bloqueio livre. A idéia básica é bloquear após o spin, continuar competindo por bloqueios após a comutação da competição, sacrificando levemente a justiça, mas obtendo alta taxa de transferência. Quando há menos conflitos de threads, desempenho semelhante pode ser obtido; Quando há conflitos graves de tópicos, o desempenho é muito maior que o dos CAS.
O resumo acima da programação simultânea Java - usando o CAS cuidadosamente é a explicação detalhada do editor. Espero que possa lhe dar uma referência e espero que você possa apoiar mais o wulin.com.