Java?volatile關(guān)鍵字特性講解下篇
一、概述
關(guān)鍵字volatile雖然增加了實例變量在多個線程之間的可見性,但它卻不具備同步性,那么也就不具備原子性。
二、特性詳解
原子性是指一個線程的操作是不能被其他線程打斷的,同一時間只有一個線程對一個變量進(jìn)行操作。在多線程情況下,每個線程的執(zhí)行結(jié)果不受其他線程的干擾,比如說多個線程同時對同一個共享成員變量n++ 100次,如果n的初始值為0,n最后的值應(yīng)該是100,所以說多個線程是互不干擾的,這就是原子性的理解。但是實際n++b并不是原子性操作,n最后的值可能會不是100。
非原子性代碼演示:
@Test
public void test2() {
DataDemo dataDemo = new DataDemo();
for (int i=0; i<20; i++) {
CountAddThread thread = new CountAddThread(dataDemo);
thread.start();
}
while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println("number值增加了20000次,此時number的實際值為:" + dataDemo.getNumber());
}
public class DataDemo {
volatile private int number = 0;
public void add() {
this.number = this.number + 10;
}
public int getNumber() {
return number;
}
public void addOne() {
this.number = this.number + 1;
}
}
public class CountAddThread extends Thread {
private DataDemo dataDemo;
public CountAddThread(DataDemo dataDemo) {
this.dataDemo = dataDemo;
}
@Override
public void run() {
for (int i=0; i<1000; i++) {
dataDemo.addOne();
}
}
}執(zhí)行結(jié)果:
number值增加了20000次,此時number的實際值為:19699
結(jié)果分析:
this.number = this.number + 1 并不是一個原子操作,也就是非線程安全的。this.number = this.number + 1 的操作步驟分解如下:
(1)從內(nèi)存中取出number的值;
(2)計算number的值;
(3)將number的值寫到內(nèi)存中;
假設(shè)在第2步計算值的時候,另外一個線程也修改i的值,那么這個時候就會出現(xiàn)臟數(shù)據(jù)。解決的辦法其實就是使用synchronized關(guān)鍵字。所以說volatile本省并不處理數(shù)據(jù)的原子性,而是強(qiáng)制對數(shù)據(jù)的讀寫及時影響到主內(nèi)存的。
解決辦法:
(1)使用synchronized
可以通過對addOne方法添加synchronized關(guān)鍵字修飾,這樣每次只有1個線程能執(zhí)行addOne方法。
(2)使用JUC包下的AtomicInteger原子類進(jìn)行實現(xiàn)。
原子操作是不能分割的整體,沒有其他線程能夠中斷或檢查正在原子操作中的變量。一個原子(atomic)類型就是一個原子操作可用的類型,它可以在沒有鎖的情況下做到線程安全。
使用synchronized 示例
@Test
public void test2() {
DataDemo dataDemo = new DataDemo();
for (int i=0; i<20; i++) {
CountAddThread thread = new CountAddThread(dataDemo);
thread.start();
}
while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println("number值增加了20000次,此時number的實際值為:" + dataDemo.getNumber());
}
public class CountAddThread extends Thread {
private DataDemo dataDemo;
public CountAddThread(DataDemo dataDemo) {
this.dataDemo = dataDemo;
}
@Override
public void run() {
for (int i=0; i<1000; i++) {
dataDemo.addOne();
}
}
}
public class DataDemo {
volatile private int number = 0;
public void add() {
this.number = this.number + 10;
}
public int getNumber() {
return number;
}
synchronized public void addOne() {
this.number = this.number + 1;
}
}
執(zhí)行結(jié)果:
number值增加了20000次,此時number的實際值為:20000
使用AtomicInteger原子類示例
@Test
public void test2() {
DataDemo dataDemo = new DataDemo();
for (int i=0; i<20; i++) {
CountAddThread thread = new CountAddThread(dataDemo);
thread.start();
}
while (dataDemo.getCount().get() != 20000) {
Thread.yield();
}
System.out.println("count值增加了20000次,此時count的實際值為:" + dataDemo.getCount());
}
public class CountAddThread extends Thread {
private DataDemo dataDemo;
public CountAddThread(DataDemo dataDemo) {
this.dataDemo = dataDemo;
}
@Override
public void run() {
for (int i=0; i<1000; i++) {
dataDemo.atomicAddOne();
}
}
}
public class DataDemo {
private AtomicInteger count = new AtomicInteger(0);
public AtomicInteger getCount() {
return count;
}
public void atomicAddOne() {
count.getAndIncrement();
}
}
執(zhí)行結(jié)果:
count值增加了20000次,此時count的實際值為:20000
到此這篇關(guān)于Java volatile關(guān)鍵字特性講解下篇的文章就介紹到這了,更多相關(guān)Java volatile內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring框架花式創(chuàng)建Bean的n種方法(小結(jié))
這篇文章主要介紹了Spring框架花式創(chuàng)建Bean的n種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
mybatis實現(xiàn)獲取入?yún)⑹荓ist和Map的取值
這篇文章主要介紹了mybatis實現(xiàn)獲取入?yún)⑹荓ist和Map的取值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
Java Spring Boot消息服務(wù)萬字詳解分析
在實際項目開發(fā)中,有時需要與其他系統(tǒng)進(jìn)行集成完成相關(guān)業(yè)務(wù)功能,這種情況最原始做法是程序內(nèi)部相互調(diào)用,除此之外,還可以用消息服務(wù)中間件進(jìn)行業(yè)務(wù)處理,用消息服務(wù)中間件處理業(yè)務(wù)能夠提升系統(tǒng)的異步通信和擴(kuò)展解耦能力。Spring Boot對消息服務(wù)管理提供了非常好的支持2021-10-10
SpringBoot yaml中的數(shù)組類型取值方式
這篇文章主要介紹了SpringBoot yaml中的數(shù)組類型取值方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09

