Java Atomic類及線程同步新機(jī)制原理解析
一、為什么要使用Atomic類?
看一下下面這個(gè)小程序,模擬計(jì)數(shù),創(chuàng)建10個(gè)線程,共同訪問(wèn)這個(gè)int count = 0 ;每個(gè)線程給count往上加10000,這個(gè)時(shí)候你需要加鎖,如果不加鎖會(huì)出現(xiàn)線程安全問(wèn)題,但是使用AtomicInteger之后就不用再做加鎖的操作了,因?yàn)锳tomicInteger內(nèi)部使用了CAS操作,直接無(wú)鎖往上遞增,有人會(huì)問(wèn)問(wèn)什么會(huì)出現(xiàn)無(wú)鎖操作,答案只有一個(gè):那就是快唄;
下面是AtomicInteger的使用方法:
package com.example.demo.threaddemo.juc_008;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author D-L
* @Classname T01_AtomicInteger
* @Version 1.0
* @Description 使用AtomicInteger類代替synchronized
* @Date 2020/7/22
*/
public class T01_AtomicInteger {
// int count = 0;
AtomicInteger count = new AtomicInteger(0);
public /**synchronized*/ void m(){
for (int i = 0; i < 10000; i++) {
// count++;
count.incrementAndGet();
}
}
public static void main(String[] args) {
T01_AtomicInteger t = new T01_AtomicInteger();
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m ,"Thread" + i));
}
threads.forEach(o -> o.start());
threads.forEach(o ->{
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
/* for (int i = 0; i < 10; i++) {
new Thread(t::m ,"Thread"+i).start();
}
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
System.out.println(t.count);
}
}
二、Atomic類,synchronized、LongAdder的效率驗(yàn)證 及 分析
模擬多個(gè)線程對(duì)一個(gè)數(shù)進(jìn)行遞增,多線程對(duì)一個(gè)共享變量進(jìn)行遞增的方法大概有三種;驗(yàn)證一下它們的效率,這里做一些粗糙的測(cè)試,基本已經(jīng)能說(shuō)明問(wèn)題,具體情況還要根據(jù)實(shí)際情況:
第一種:使用long count = 0; 加鎖來(lái)實(shí)現(xiàn);
第二種:使用AtomicLong類來(lái)實(shí)現(xiàn);
第三種:使用LongAdder實(shí)現(xiàn);
package com.example.demo.threaddemo.juc_008;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
/**
* @author D-L
* @Classname T02_AtomicVsSyncVsLongAdder
* @Version 1.0
* @Description 測(cè)試Atomic類 synchronized LongAdder效率
* @Date 2020/7/22
*/
public class T02_AtomicVsSyncVsLongAdder {
static AtomicLong count1 = new AtomicLong(0L);
static Long count2 = 0L;
static LongAdder count3 = new LongAdder();
public static void main(String[] args) throws InterruptedException {
Thread [] threads = new Thread[1000];
/*-----------------------------------Atomic類-----------------------------------*/
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() ->{
for (int j = 0; j < 100000; j++) {
count1.incrementAndGet();
}
});
}
long start = System.currentTimeMillis();
for (Thread t : threads) t.start();
for (Thread t : threads) t.join();
long end = System.currentTimeMillis();
System.out.println("Atomic:" + count1.get() +"-----time:" +(end - start));
/*----------------------------------synchronized---------------------------------*/
Object lock = new Object();
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized (lock) {
count2++;
}
}
}
});
}
long start2 = System.currentTimeMillis();
for (Thread t : threads) t.start();
for (Thread t : threads) t.join();
long end2 = System.currentTimeMillis();
System.out.println("synchronized:" + count1.get() +"-----time:" +(end2 - start2));
/*-------------------------------------LongAdder----------------------------------*/
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() ->{
for (int j = 0; j < 100000; j++) {
count3.increment();
}
});
}
long start3 = System.currentTimeMillis();
for (Thread t : threads) t.start();
for (Thread t : threads) t.join();
long end3 = System.currentTimeMillis();
System.out.println("LongAdder:" + count1.get() +"-----time:" +(end3 - start3));
}
}
/*----------------------------------運(yùn)行結(jié)果---------------------------------*/
Atomic:100000000-----time:2096synchronized:100000000-----time:5765LongAdder:100000000-----time:515
從以上的結(jié)果來(lái)看并發(fā)量達(dá)到一定程度運(yùn)行效率:LongAdder > AtomicLong > synchronized; 這個(gè)還只是一個(gè)粗略的測(cè)試,具體使用還要根據(jù)實(shí)際情況。
為什么AtomicLong的效率比synchronized的效率高?
AtomicLong的底層使用的是CAS操作(無(wú)鎖優(yōu)化),而synchronized雖然底層做了優(yōu)化但是并發(fā)量達(dá)到一定層度,存在鎖的膨脹,最終會(huì)變成重量級(jí)鎖,需要向操作系統(tǒng)申請(qǐng)鎖資源,所以synchronized的效率慢一點(diǎn)合情合理。
為什么LongAdder的效率比AtomicLong的效率高?
因?yàn)長(zhǎng)ongAdder使用了分段鎖的概念,效率比AtomicLong的效率高。

分段鎖的意思就是用一個(gè)數(shù)組把線程分成若干組,然后運(yùn)行結(jié)束后把結(jié)果累加起來(lái),例如你有1000個(gè)線程,數(shù)組的長(zhǎng)度為4,那就把0-250個(gè)放到數(shù)組的第0位,以此類推,然后把四個(gè)數(shù)組中線程的計(jì)算結(jié)果累加,這樣會(huì)很大程度上節(jié)省時(shí)間,從而提高效率。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring實(shí)現(xiàn)類私有方法的幾個(gè)問(wèn)題(親測(cè)通用解決方案)
現(xiàn)實(shí)的業(yè)務(wù)場(chǎng)景中,可能需要對(duì)Spring的實(shí)現(xiàn)類的私有方法進(jìn)行測(cè)試。本文給大家分享Spring實(shí)現(xiàn)類私有方法面臨的幾個(gè)問(wèn)題及解決方案,感興趣的朋友跟隨小編一起看看吧2021-06-06
JAVA 時(shí)間區(qū)間的字符串合法性驗(yàn)證
需要對(duì)獲得的諸如08:30-11:00這樣的字符串進(jìn)行合法性驗(yàn)證,判定表示的時(shí)間區(qū)間是否合法,以及對(duì)高峰期時(shí)間的區(qū)間是否在總的時(shí)間區(qū)間內(nèi)部進(jìn)行判斷。2013-03-03
Mybatis Criteria使用and和or進(jìn)行聯(lián)合條件查詢的操作方法
這篇文章主要介紹了Mybatis Criteria的and和or進(jìn)行聯(lián)合條件查詢的方法,本文通過(guò)例子給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-10-10
Mybatis整合達(dá)夢(mèng)數(shù)據(jù)庫(kù)的完整步驟記錄
作為國(guó)產(chǎn)數(shù)據(jù)庫(kù),達(dá)夢(mèng)做的不錯(cuò),提供的遷移工具也相當(dāng)不錯(cuò),下面這篇文章主要給大家介紹了關(guān)于Mybatis整合達(dá)夢(mèng)數(shù)據(jù)庫(kù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
springboot?maven?打包插件介紹及注意事項(xiàng)說(shuō)明
這篇文章主要介紹了springboot?maven?打包插件介紹及注意事項(xiàng)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Java中==與equals()及hashcode()三者之間的關(guān)系詳解
最近也是在讀Hollis的《深入理解Java核心技術(shù)》里面一節(jié)講到了equals()和hashcode()的關(guān)系,對(duì)于這個(gè)高頻面試點(diǎn),咱們需要認(rèn)真理清一下幾者之間的關(guān)系2022-10-10
Dubbo無(wú)法訪問(wèn)遠(yuǎn)程Zookeeper已注冊(cè)服務(wù)的問(wèn)題解決方案
今天小編就為大家分享一篇關(guān)于Dubbo無(wú)法訪問(wèn)遠(yuǎn)程Zookeeper已注冊(cè)服務(wù)的問(wèn)題解決方案,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03

