国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

(原創)確保JAVA線程安全的4種常用方法

2019-11-14 14:57:14
字體:
來源:轉載
供稿:網友

java中可以有很多方法來保證線程安全,比如使用同步方法、同步塊,使用原子類(atomic concurrent classes),實現并發鎖,使用volatile關鍵字,使用不變類和線程安全類。

這里是最基礎的線程安全教程

實際上在volatile的使用上很容易有誤解,以為volatile就可以做原子操作,實際不然。Volatile 變量具有 synchronized 的可見性特性,但是不具備原子特性。這就是說線程能夠自動發現 volatile 變量的最新值。Volatile 變量可用于提供線程安全,但是只能應用于非常有限的一組用例:多個變量之間或者某個變量的當前值與修改后值之間沒有約束。因此,單獨使用 volatile 還不足以實現計數器、互斥鎖或任何具有與多個變量相關的不變式(Invariants)的類(例如 “start <=end”)。

對于volatile修飾的變量,jvm虛擬機只是保證從主內存加載到線程工作內存的值是最新的。

直接上代碼:

import java.util.concurrent.atomic.AtomicInteger;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Counter {        public static int count = 0; //對于值引用來說,多線程操作的是變量的副本,操作完后刷新到主存中.所以不具有原子性。    //錯誤的volatile使用方法,volatil只是直接進行內存地址操作,但并不能保證線程安全.volatile很容易被誤用,用來進行原子性操作,    public volatile static int volatileCount = 0;     static Object obj =new Object();    public static AtomicInteger atomicCount;// 正確的方法1,使用原子操作        static class MyObject{// 正確的方法4,使用地址引用,多線程是通過地址操作。值的改變是同一個變量(地址)        static int mycount=0;        }    public static void inc1() {        MyObject.mycount++;    }       public static void inc() {        //這里延遲1毫秒,使得結果明顯        try {            Thread.sleep(1);        } catch (InterruptedException e) {        }                //典型錯誤1:在資源對象加鎖顯然是不對的,實際上毫無意義        //Lock lock =new ReentrantLock();             //lock.lock();        //synchronized (obj)  // 正確的方法2,可重人的同步塊操作。這也是最常用的辦法        {            count++;            volatileCount++;            atomicCount.incrementAndGet();        }        //lock.unlock();    }     public static void main(String[] args) {         //同時啟動100個線程,去進行i++計算,看看實際結果        atomicCount =new AtomicInteger(0);        Lock lock =new ReentrantLock(); // 正確的方法3,可重人鎖   ReentrantLock        Thread threads[]=new Thread[100];         for (int i = 0; i < 100; i++) {            threads[i]=new Thread(new Runnable() {                @Override                public void run() {                    //lock.lock();// 正確的方法3,可重人鎖   ReentrantLock                    Counter.inc();                    //lock.unlock();                     inc1();                }            });            threads[i].start();        }                //保障線程全部結束        for(int i=0;i<100;i++){            try {                threads[i].join();            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.PRintStackTrace();            }        }         //如果沒有同步鎖.值有可能不同。        System.out.println("運行結果1:Counter.count=" + Counter.count);        //atomicCount值都應該是一致的        System.out.println("運行結果2:Counter.atomicCount=" + Counter.atomicCount);        //atomicCount值。如果沒有同步鎖.值有可能不同。        System.out.println("運行結果3:Counter.volatileCount=" + Counter.volatileCount);        //使用地址引用,多線程是通過地址操作。值的改變是同一個變量(地址)。值都應該是一致的        System.out.println("運行結果4:Counter.mycount=" +MyObject.mycount);    }        }

 

運行之后,結果可能會這樣

運行結果1:Counter.count=96
運行結果2:Counter.atomicCount=100
運行結果3:Counter.volatileCount=97
運行結果4:Counter.mycount=100

 

如果在52行和54行取消注釋(或者取消32行的注釋),結果必然如下:

運行結果1:Counter.count=100
運行結果2:Counter.atomicCount=100
運行結果3:Counter.volatileCount=100
運行結果4:Counter.mycount=100

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 肥城市| 平山县| 晋中市| 浦县| 张家港市| 南靖县| 民县| 丘北县| 余庆县| 建宁县| 黔江区| 三亚市| 达拉特旗| 滁州市| 缙云县| 凤阳县| 武安市| 兴义市| 张家川| 都江堰市| 日土县| 定西市| 宁乡县| 崇明县| 特克斯县| 尉氏县| 平安县| 苏尼特右旗| 民勤县| 镇平县| 东方市| 金山区| 尚志市| 珲春市| 松滋市| 大冶市| 黄大仙区| 淳安县| 大连市| 沾化县| 田阳县|