大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動力節點LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 學習攻略 Java學習 java的線程安全問題原因及解決辦法

java的線程安全問題原因及解決辦法

更新時間:2019-08-27 11:52:34 來源:動力節點 瀏覽2899次



今天動力節點java學院小編為大家介紹java的線程安全問題原因及解決辦法,希望對各位java程序員有幫助,下面就隨小編一起看看java的線程安全問題原因及解決辦法吧。


1、為什么會出現線程安全問題


  計算機系統資源分配的單位為進程,同一個進程中允許多個線程并發執行,并且多個線程會共享進程范圍內的資源:例如內存地址。當多個線程并發訪問同一個內存地址并且內存地址保存的值是可變的時候可能會發生線程安全問題,因此需要內存數據共享機制來保證線程安全問題。


  對應到java服務來說,在虛擬中的共享內存地址是java的堆內存,比如以下程序中線程安全問題:


public class ThreadUnsafeDemo {


    private static final ExecutorService EXECUTOR_SERVICE;


    static {

        EXECUTOR_SERVICE = new ThreadPoolExecutor(100, 100, 1000 * 10,

                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(100), new ThreadFactory() {


            private AtomicLong atomicLong = new AtomicLong(1);


            @Override

            public Thread newThread(Runnable r) {

                return new Thread(r, "Thread-Safe-Thread-" + atomicLong.getAndIncrement());

            }

        });

    }


    public static void main(String[] args) throws Exception {

        Map<String, Integer> params = new HashMap<>();


        List<Future> futureList = new ArrayList<>(100);

        for (int i = 0; i < 100; i++) {

            futureList.add(EXECUTOR_SERVICE.submit(new CacheOpTask(params)));

        }


        for (Future future : futureList) {

            System.out.println("Future result:" + future.get());

        }


        System.out.println(params);

    }


    private static class CacheOpTask implements Callable<Integer> {


        private Map<String, Integer> params;


        CacheOpTask(Map<String, Integer> params) {

            this.params = params;

        }


        @Override

        public Integer call() {

            for (int i = 0; i < 100; i++) {

                int count = params.getOrDefault("count", 0);

                params.put("count", ++count);

            }

            return params.get("count");

        }

    }

}


  創建100個task,每個task對map中的元素累加100此,程序執行結果為:


{count=9846}


而預期的正確結果為:


{count=10000}


至于出現這種問題的原因,下面會具體分析。


判斷是否有線程安全性的一個原則是:


是否有多線程訪問可變的共享變量



2、多線程的優勢


發揮多處理器的強大能力,提高效率和程序吞吐量。


3、并發帶來的風險


使用并發程序帶來的主要風險有以下三種:


(1)安全性問題:


競態條件:由于不恰當的執行時序而出現不正確的結果。


對于1中的線程安全的例子就是由于競態條件導致的最終結果與預期結果不一致。關鍵代碼塊如下:


int count = params.getOrDefault("count", 0);


params.put("count", ++count);


當多個線程同時取的count的值的時候,每個線程計算之后,在寫入到count,這時候會出現多個線程值被覆蓋的情況,最終導致結果不正確。如下圖所示:


1566876971915396.png




(2)解決此類問題的幾種方法


1)使用同步機制限制變量的訪問:鎖


比如:


synchronized (LOCK) {

    int count = params.getOrDefault("count", 0);

    params.put("count", ++count);

}


2)將變量設置為不可變


即將共享變量設置為final



3)不在線程之間共享此變量ThreadLocal


編程的原則:首先編寫正確的代碼,然后在實現性能的提升。


無狀態的類一定是線程安全的


 ?。?)內置鎖


  內置鎖:同步代碼塊( synchronized (this) {})


  進入代碼塊前需要獲取鎖,會有性能問題。內置鎖是可重入鎖,之所以每個對象都有一個內置鎖,是為了避免顯示的創建鎖對象。


  常見的加鎖約定:將所有的可變狀態都封裝在對象內部,并使用內置鎖對所有訪問可變狀態的代碼進行同步。例如:Vector等


  同步的另一個功能:內存可見性,類似于volatile。


  非volatile的64位變量double、long:


  JVM允許對64位的操作分解為兩次32位的兩次操作,可變64位變量必須用volatile或者鎖來保護。


  加鎖的含義不僅在于互斥行為,還包括內存可見性,為了所有線程都可以看到共享變量的最新值,所有線程應該使用同一個鎖。


  原則:除非需要跟高的可見性,否則應該將所有的域都聲明為私有的,除非需要某個域是可變的,否則應該講所有的域生命為final的。


  活躍性問題:線程活躍性問題主要是由于加鎖不正確導致的線程一直處于等待獲取鎖的狀態,比如以下程序:


public class DeadLock {

    private static final Object[] LOCK_ARRAY;


    static {

        LOCK_ARRAY = new Object[2];

        LOCK_ARRAY[0] = new Object();

        LOCK_ARRAY[1] = new Object();

    }


    public static void main(String[] args) throws Exception {

        TaskOne taskOne = new TaskOne();

        taskOne.start();


        TaskTwo taskTwo = new TaskTwo();

        taskTwo.start();

        System.out.println("finished");

    }


    private static class TaskOne extends Thread {


        @Override

        public void run(){

            synchronized (LOCK_ARRAY[0]) {

                try {

                    Thread.sleep(3000);


                } catch (Exception e) {

                }

                System.out.println("Get LOCK-0");

                synchronized (LOCK_ARRAY[1]) {

                    System.out.println("Get LOCK-1");

                }


            }

        }

    }


    private static class TaskTwo extends Thread {


        @Override

        public void run() {

            synchronized (LOCK_ARRAY[1]) {

                try {

                    Thread.sleep(1000 * 3);


                } catch (Exception e) {

                }

                System.out.println("Get LOCK-1");

                synchronized (LOCK_ARRAY[0]) {

                    System.out.println("Get LOCK-0");

                }

            }

        }

    }

}


在兩個線程持有一個鎖,并在在鎖沒有釋放之前,互相等待對方持有的鎖,這時候會造成兩個線程會一直等待,從而產生死鎖。在我們使用鎖的時候應該考慮持有鎖的時長,特別是在網絡I/O的時候。


在使用鎖的時候要盡量避免以上情況,從而避免產生死鎖。


3、性能問題


在使用多線程執行程序的時候,在線程間的切換以及線程的調度也會消耗CPU的性能。


以上就是動力節點java學院小編介紹的“java線程安全問題原因及解決辦法”的內容,希望對各位java程序員有幫助,如有疑問,請在線咨詢,有專業老師隨時為你服務。


提交申請后,顧問老師會電話與您溝通安排學習

免費課程推薦 >>
技術文檔推薦 >>
主站蜘蛛池模板: 日本在线色视频 | 日日舔夜夜操 | 亚洲美女在线播放 | 800玖玖爱在线观看香蕉 | 尹人香蕉久久99天天拍欧美p7 | 无码免费一区二区三区免费播放 | 伊人天天操| 久久久精品视频在线观看 | 成年人视频黄色 | 国产精品400部自产在线观看 | 日韩精品亚洲精品485页 | 日韩精品欧美精品中文精品 | 久久久无码精品亚洲日韩按摩 | 色综合色狠狠天天综合色hd | 亚洲影院中文字幕 | 久久亚洲国产中v天仙www | a毛片在线观看 | 国产综合亚洲专区在线 | 无遮挡又黄又爽又色1000部 | 极品精品国产超清自在线观看 | 国产一级特黄高清免费大片 | 天天视频国产免费入口 | 欧美一级高清片欧美国产欧美 | 国产福利视频网站 | 毛片女人 | 热综合一本伊人久久精品 | 国产欧美日韩精品第二区 | 99热在线精品观看 | 欧美一级久久久久久久大 | 精品视频免费播放 | 日韩亚洲人成在线综合 | 久久综久久美利坚合众国 | 亚洲国产美女精品久久 | 国产在线精品福利大全 | 亚洲精品久久激情影院 | 国产一区二区三区亚洲欧美 | 欧美激情综合 | 不卡视频免费在线观看 | 精品国产成人综合久久小说 | 久久精品国产日本波多麻结衣 | 在线观看日韩视频 |