자바 자바 인터뷰 질문에 대한 이야기 특유의 방법 CAS (8) 동시 성능을 최적화하려면?

이 문서는에서 재생되는 음의 휴 퍼진의 구조

첫째, 선행 검토

 

모든 사람에게이 기사는 특히 참조 휘발성 원리를 담소를 나눴다 : "결국 동시성의 휘발성 자바 인터뷰 질문이 무엇인지에 대해 이야기 고장? " .

 

이 문서에서는 개선하고 CAS 작업의 성능을 최적화하는 방법을 우리는 CAS 관련에서 자바 및 계약에 대해 이야기 원자 작업을 제공하고, 자바 (8).

 

원자 시리즈와 같은 원자 때문에, 모두 동시 프로그래밍, JDK 소스 코드, 또는 오픈 소스 프로젝트의 다양한 종종 사용된다. 그리고 자바 동시 인터뷰에서,이 때문에 모든 사람이 채팅을 여전히 가치가있다, 또한 상대적으로 높은 주파수 테스트 사이트입니다.

 

 

둘째, 현장의 도입, 문제 하이라이트

 

음, 우리는 시작! 스레드가 예를 들어, 변수 정지를 축적 할 필요가 복수의 가정, 다음 코드 : 

 

 

 

직접 데이터 변수에 같은 동시 다중 스레드를 수정할 수 있기 때문에 사실, 코드의 상단 부분은, 스레드 안전하지 않은 성적 행동, 값은 변화에 대한 기대 값을 준수하지 않는 데이터의 변화로 이어질 확인하지 않습니다.

 

예를 들어, 우리는 최종 데이터의 값이 20 차례 것이라고 믿는다, 20 개 각각 스레드 데이터가 데이터 ++ 작업을 수행 할 말은 없습니다.

 

마지막으로 가능한 값 데이터 (18), 또는 다음 멀티 스레드 작업이 부정확 한 데이터로 이어지는 등의 보안 문제가 있기 때문에 19이 가능합니다.

 

왜 정확하지에 관해서는? 이 문서에서 설명되지 않는 범위이만큼 학생들이 자바를 배운 일반적이기 때문에, 확실히 너무 많은 스레드 동시성 문제를 알고 있습니다.

 

 

셋째, 초기 솔루션 : 동기화

 

그래서, 위의 코드를 위해, 우리는 일반적으로 모양을 변형시킬 것이다, 그 잠금 방식으로 스레드 안전이 될 수 있습니다 :

 

 

 

이번에는, 코드가 우리를 추가하기 때문에, 스레드 안전 동기화 증가 () 메소드는 하나의 스레드 만 잠글 수 있습니다 같은 시간을 고정하기 전에 올 입력 각 실을 수 있도록, 즉, 다른 스레드가 잠금을 기다릴 필요가있다.

 

이렇게함으로써, 때마다 누적 된 변경 데이터 1, 데이터 장애 문제가 발생하지 않도록하는 것이 가능하다.

 

오래된 규칙! 다음 차트에서 살펴 보자는 동기화 잠금에서 효과와 분위기를 느낄 수, N에 해당하는이 사람이 그 값 갱신을 대기 스레드.

 

 

 

 

그러나, 간단한 데이터 ++ 작업은 무거운 록에 추가됩니다 멀티 스레드 과잉 문제, 약간의 과잉을 해결 동기화.

 

또한 업데이트 된 자바 버전,하지만 함께 최적화 많은 일을하지만,이 과정은 단순히 작업을 축적 동기화 된 있지만, 여전히 것으로 보인다 "너무 무거워." 사람들은 더 복잡한 장면과 동시 프로그래밍 문제를 해결하기 위해 동기화 할 수 있습니다.

 

또한,이 시나리오에서는 각 스레드가 아직 연재의 일치하지 않는 그래서, 동기화를 사용하는 경우? 한 줄, 잠금, 데이터 처리에 의해 하나는 잠금을 해제하고 다음에 온다.

 

 

 

넷째,보다 효율적인 구조 : 원자 자신의 기본 원칙 - 아톰

 

이 간단한 데이터 ++ 클래스의 작동을 위해, 사실, 우리는 연습, 자바 및 계약 제안을 아래에 원자 원자 클래스, 같은 AtomicInteger의 범위를 변경할 수 있습니다.

 

경우에 그는 멀티 스레드 고성능 동시 업데이트의 보안 값을 보장 할 수있다. 다음 코드를 살펴 보자 :

 

 

 

우리는 위의 코드를 보면, 아주 간단하지 않다! 다중 스레드의 동시 실행이 나에게 데이터의 값을 제공 incrementAndGet AtomicInteger의 () 메소드, 의미가 1 씩 증가 할 수 있습니다 다음, 최신 값 축적을 반환합니다.

 

이 코드는, 내가 자물쇠를보고 그 말을 잠금을 해제하지 않습니다!

 

사실, 잠금 장치와 원자 원자 기본이되는 클래스는 전통적인 의미에서가 아니라 CAS의 어떤 잠금 장치는, CAS 메커니즘이 없도록 보안의 수정 된 값을 통해 멀티 스레드

 

CAS 무엇입니까? 그의 전체 이름입니다 : 비교] 및 설정 사용자가 설정하기 전에 비교하기위한 것입니다.

 

몇 마디의 사람은지도에 먼저했다!

 

 

 

즉 다음과 같이 그들의 기본 메커니즘의 AtomicInteger의 값을 수정하는 세 개의 동시 스레드가있는 경우 우리는 위의 표를 보면 :

 

첫째, 먼저 현재 값을 얻을 것이다 각 스레드는 다음 다른 사람이 중단되지 않습니다,이 원자 CAS 작업이 완전히 실행이 완료되어 있어야합니다 의미 원자 CAS 작업을 수행.

 

然后CAS操作里,会比较一下说,唉!大兄弟!现在你的值是不是刚才我获取到的那个值啊?

 

如果是的话,bingo!说明没人改过这个值,那你给我设置成累加1之后的一个值好了!

 

同理,如果有人在执行CAS的时候,发现自己之前获取的值跟当前的值不一样,会导致CAS失败,失败之后,进入一个无限循环,再次获取值,接着执行CAS操作!

 

好!现在我们对照着上面的图,来看一下这整个过程:

 

  • 首先第一步,我们假设线程一咔嚓一下过来了,然后对AtomicInteger执行incrementAndGet()操作,他底层就会先获取AtomicInteger当前的值,这个值就是0。

     

  • 此时没有别的线程跟他抢!他也不管那么多,直接执行原子的CAS操作,问问人家说:兄弟,你现在值还是0吗?

     

  • 如果是,说明没人修改过啊!太好了,给我累加1,设置为1。于是AtomicInteger的值变为1!

     

  • 接着线程2和线程3同时跑了过来,因为底层不是基于锁机制,都是无锁化的CAS机制,所以他们俩可能会并发的同时执行incrementAndGet()操作。

     

  • 然后俩人都获取到了当前AtomicInteger的值,就是1

     

  • 接着线程2抢先一步发起了原子的CAS操作!注意,CAS是原子的,此时就他一个线程在执行!

     

  • 然后线程2问:兄弟,你现在值还是1吗?如果是,太好了,说明没人改过,我来改成2

     

  • 好了,此时AtomicInteger的值变为了2。关键点来了:现在线程3接着发起了CAS操作,但是他手上还是拿着之前获取到的那个1啊!

     

  • 线程3此时会问问说:兄弟,你现在值还是1吗?

     

  • 噩耗传来!!!这个时候的值是2啊!线程3哭泣了,他说,居然有人在这个期间改过值。算了,那我还是重新再获取一次值吧,于是获取到了最新的值,值为2。

     

  • 然后再次发起CAS操作,问问,现在值是2吗?是的!太好了,没人改,我抓紧改,此时AtomicInteger值变为3!

 

上述整个过程,就是所谓Atomic原子类的原理,没有基于加锁机制串行化,而是基于CAS机制:先获取一个值,然后发起CAS,比较这个值被人改过没?如果没有,就更改值!这个CAS是原子的,别人不会打断你!

 

通过这个机制,不需要加锁这么重量级的机制,也可以用轻量级的方式实现多个线程安全的并发的修改某个数值。

 

 

五、Java 8对CAS机制的优化

 

但是这个CAS有没有问题呢?肯定是有的。比如说大量的线程同时并发修改一个AtomicInteger,可能有很多线程会不停的自旋,进入一个无限重复的循环中。

 

这些线程不停地获取值,然后发起CAS操作,但是发现这个值被别人改过了,于是再次进入下一个循环,获取值,发起CAS操作又失败了,再次进入下一个循环。

 

在大量线程高并发更新AtomicInteger的时候,这种问题可能会比较明显,导致大量线程空循环,自旋转,性能和效率都不是特别好。

 

于是,当当当当,Java 8推出了一个新的类,LongAdder,他就是尝试使用分段CAS以及自动分段迁移的方式来大幅度提升多线程高并发执行CAS操作的性能!

 

 

 

在LongAdder的底层实现中,首先有一个base值,刚开始多线程来不停的累加数值,都是对base进行累加的,比如刚开始累加成了base = 5。

 

接着如果发现并发更新的线程数量过多,就会开始施行分段CAS的机制,也就是内部会搞一个Cell数组,每个数组是一个数值分段。

 

这时,让大量的线程分别去对不同Cell内部的value值进行CAS累加操作,这样就把CAS计算压力分散到了不同的Cell分段数值中了!

 

这样就可以大幅度的降低多线程并发更新同一个数值时出现的无限循环的问题,大幅度提升了多线程并发更新数值的性能和效率!

 

而且他内部实现了自动分段迁移的机制,也就是如果某个Cell的value执行CAS失败了,那么就会自动去找另外一个Cell分段内的value值进行CAS操作。

 

这样也解决了线程空旋转、自旋不停等待执行CAS操作的问题,让一个线程过来执行CAS时可以尽快的完成这个操作。

 

最后,如果你要从LongAdder中获取当前累加的总值,就会把base值和所有Cell分段数值加起来返回给你。

 

 

六、总结 & 思考

 

不知道大家有没有发现这种高并发访问下的分段处理机制,在很多地方都有类似的思想体现!因为高并发中的分段处理机制实际上是一个很常见和常用的并发优化手段。

추천

출처www.cnblogs.com/alimayun/p/12129809.html