最近在網上找到好多的多線程關于原子性的例子,說的都不是非常的明確,對于剛學習多線程的新手而言很容誤導學員,在這里,我通過多個例子對多線程的原子性加以說明。
?
例子一:傳統技術自增
package face.thread.volatilep;public class Counter2 {private int count = 0; public synchronized void inc() {count = count + 1;}public static void main(String[] args) {//同時啟動1000個線程,去進行i++計算,看看實際結果final Counter2 c = new Counter2();for (int i = 0; i < 1000; i++) {new Thread(new Runnable() {@Overridepublic void run() {c.inc();}}).start();}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//這里每次運行的值都有可能不同,可能為1000System.out.println("運行結果:Counter.count=" + c.count);}
}
以上代碼打印的結果偶爾會等于1000,基本上都會有一些誤差,原因是線程執行的順序無法保證的,很可能在新建的1000個線程還沒有執行完,我們的代碼
System.out.println("運行結果:Counter.count=" + Counter.count);
就已經執行完了,要想解決這個問題很簡單,那就是在最后一句println之前在線程睡眠一段時間,比如睡眠2秒鐘。等1000個線程執行完了,在打印"
"運行結果:Counter.count=" + Counter.count";
?
還可以借助于線程輔助類解決,在這里就舉例一個最簡單的例子展示:
?
package face.thread.volatilep;import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;public class Counter3 {int count =0; public synchronized void inc() {count++;}public static void main(String[] args) {//同時啟動1000個線程,去進行i++計算,看看實際結果final Counter3 c = new Counter3();final CyclicBarrier cy = new CyclicBarrier(10000, new Runnable() {public void run() {//這里每次運行的值都有可能不同,可能為1000System.out.println("運行結果:Counter.count=" + c.count);}});for (int i = 0; i < 10000; i++) {new Thread(new Runnable() {@Overridepublic void run() {c.inc();try {cy.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}}).start();}}
}
?
例子二:原子性自增
原子是世界上的最小單位,具有不可分割性。比如 a=0;(a非long和double類型) 這個操作是不可分割的,那么我們說這個操作時原子操作。再比如:a++; 這個操作實際是a = a + 1;是可分割的,所以他不是一個原子操作。非原子操作都會存在線程安全問題,需要我們使用同步技術(sychronized)來讓它變成一個原子操作。一個操作是原子操作,那么我們稱它具有原子性。Java的concurrent包下提供了一些原子類,我們可以通過閱讀API來了解這些原子類的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。
因為原子性是線程安全的,所以關于原子性自增是不需要傳統的加鎖技術的,具體看代碼:
package face.thread.volatilep;import java.util.concurrent.atomic.AtomicInteger;public class CounterNew2{AtomicInteger count = new AtomicInteger(0);public void increment() {count.getAndIncrement();}public int getCount() {return count.get();}public static void main(String[] args) {final CounterNew2 cn = new CounterNew2();for(int i = 0 ; i < 10000;i++){new Thread(new Runnable() {public void run() {cn.increment();}}).start();}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("count最終返回值:" + cn.getCount());}
}
運行結果也是:10000