午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

JAVA中的線(xiàn)程安全與非線(xiàn)程安全

 看風(fēng)景D人 2016-10-01

原文:http://blog.csdn.net/xiao__gui/article/details/8934832

ArrayList和Vector有什么區(qū)別?HashMap和HashTable有什么區(qū)別?StringBuilder和StringBuffer有什么區(qū)別?這些都是Java面試中常見(jiàn)的基礎(chǔ)問(wèn)題。面對(duì)這樣的問(wèn)題,回答是:ArrayList是非線(xiàn)程安全的,Vector是線(xiàn)程安全的;HashMap是非線(xiàn)程安全的,HashTable是線(xiàn)程安全的;StringBuilder是非線(xiàn)程安全的,StringBuffer是線(xiàn)程安全的。因?yàn)檫@是昨晚剛背的《Java面試題大全》上面寫(xiě)的。此時(shí)如果繼續(xù)問(wèn):什么是線(xiàn)程安全?線(xiàn)程安全和非線(xiàn)程安全有什么區(qū)別?分別在什么情況下使用?這樣一連串的問(wèn)題,一口老血就噴出來(lái)了…

非線(xiàn)程安全的現(xiàn)象模擬

這里就使用ArrayList和Vector二者來(lái)說(shuō)明。

下面的代碼,在主線(xiàn)程中new了一個(gè)非線(xiàn)程安全的ArrayList,然后開(kāi)1000個(gè)線(xiàn)程分別向這個(gè)ArrayList里面添加元素,每個(gè)線(xiàn)程添加100個(gè)元素,等所有線(xiàn)程執(zhí)行完成后,這個(gè)ArrayList的size應(yīng)該是多少?應(yīng)該是100000個(gè)?

public class Main
{
    public static void main(String[] args)
    {
        // 進(jìn)行10次測(cè)試
        for(int i = 0; i < 10; i++)
        {
            test();
        }
    }

    public static void test()
    {
        // 用來(lái)測(cè)試的List
        List<Object> list = new ArrayList<Object>();

        // 線(xiàn)程數(shù)量(1000)
        int threadCount = 1000;

        // 用來(lái)讓主線(xiàn)程等待threadCount個(gè)子線(xiàn)程執(zhí)行完畢
        CountDownLatch countDownLatch = new CountDownLatch(threadCount);

        // 啟動(dòng)threadCount個(gè)子線(xiàn)程
        for(int i = 0; i < threadCount; i++)
        {
            Thread thread = new Thread(new MyThread(list, countDownLatch));
            thread.start();
        }

        try
        {
            // 主線(xiàn)程等待所有子線(xiàn)程執(zhí)行完成,再向下執(zhí)行
            countDownLatch.await();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        // List的size
        System.out.println(list.size());
    }
}

class MyThread implements Runnable
{
    private List<Object> list;

    private CountDownLatch countDownLatch;

    public MyThread(List<Object> list, CountDownLatch countDownLatch)
    {
        this.list = list;
        this.countDownLatch = countDownLatch;
    }

    public void run()
    {
        // 每個(gè)線(xiàn)程向List中添加100個(gè)元素
        for(int i = 0; i < 100; i++)
        {
            list.add(new Object());
        }

        // 完成一個(gè)子線(xiàn)程
        countDownLatch.countDown();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

上面進(jìn)行了10次測(cè)試(為什么要測(cè)試10次?因?yàn)榉蔷€(xiàn)程安全并不是每次都會(huì)導(dǎo)致問(wèn)題)。
輸出結(jié)果:

99946

100000

100000

100000

99998

99959

100000

99975

100000

99996

上面的輸出結(jié)果發(fā)現(xiàn),并不是每次測(cè)試結(jié)果都是100000,有好幾次測(cè)試最后ArrayList的size小于100000,甚至?xí)r不時(shí)會(huì)拋出個(gè)IndexOutOfBoundsException異常。(如果沒(méi)有這個(gè)現(xiàn)象可以多試幾次)
這就是非線(xiàn)程安全帶來(lái)的問(wèn)題了。上面的代碼如果用于生產(chǎn)環(huán)境,就會(huì)有隱患就會(huì)有BUG了。

再用線(xiàn)程安全的Vector來(lái)進(jìn)行測(cè)試,上面代碼改變一處,test()方法中
List<Object> list = new ArrayList<Object>();
改為
List<Object> list = new Vector<Object>();

再運(yùn)行程序。

輸出結(jié)果:

100000

100000

100000

100000

100000

100000

100000

100000

100000

100000

再多跑幾次,發(fā)現(xiàn)都是100000,沒(méi)有任何問(wèn)題。因?yàn)閂ector是線(xiàn)程安全的,在多線(xiàn)程操作同一個(gè)Vector對(duì)象時(shí),不會(huì)有任何問(wèn)題。

再換成LinkedList試試,同樣還會(huì)出現(xiàn)ArrayList類(lèi)似的問(wèn)題,因?yàn)長(zhǎng)inkedList也是非線(xiàn)程安全的。

二者如何取舍

非線(xiàn)程安全是指多線(xiàn)程操作同一個(gè)對(duì)象可能會(huì)出現(xiàn)問(wèn)題。而線(xiàn)程安全則是多線(xiàn)程操作同一個(gè)對(duì)象不會(huì)有問(wèn)題。

線(xiàn)程安全必須要使用很多synchronized關(guān)鍵字來(lái)同步控制,所以必然會(huì)導(dǎo)致性能的降低。

所以在使用的時(shí)候,如果是多個(gè)線(xiàn)程操作同一個(gè)對(duì)象,那么使用線(xiàn)程安全的Vector;否則,就使用效率更高的ArrayList。

非線(xiàn)程安全!=不安全

有人在使用過(guò)程中有一個(gè)不正確的觀點(diǎn):我的程序是多線(xiàn)程的,不能使用ArrayList要使用Vector,這樣才安全。

非線(xiàn)程安全并不是多線(xiàn)程環(huán)境下就不能使用。注意我上面有說(shuō)到:多線(xiàn)程操作同一個(gè)對(duì)象。注意是同一個(gè)對(duì)象。比如最上面那個(gè)模擬,就是在主線(xiàn)程中new的一個(gè)ArrayList然后多個(gè)線(xiàn)程操作同一個(gè)ArrayList對(duì)象。

如果是每個(gè)線(xiàn)程中new一個(gè)ArrayList,而這個(gè)ArrayList只在這一個(gè)線(xiàn)程中使用,那么肯定是沒(méi)問(wèn)題的。

線(xiàn)程安全的實(shí)現(xiàn)

線(xiàn)程安全是通過(guò)線(xiàn)程同步控制來(lái)實(shí)現(xiàn)的,也就是synchronized關(guān)鍵字。

在這里,我用代碼分別實(shí)現(xiàn)了一個(gè)非線(xiàn)程安全的計(jì)數(shù)器和線(xiàn)程安全的計(jì)數(shù)器Counter,并對(duì)他們分別進(jìn)行了多線(xiàn)程測(cè)試。

非線(xiàn)程安全的計(jì)數(shù)器:

public class Main
{
    public static void main(String[] args)
    {
        // 進(jìn)行10次測(cè)試
        for(int i = 0; i < 10; i++)
        {
            test();
        }
    }

    public static void test()
    {
        // 計(jì)數(shù)器
        Counter counter = new Counter();

        // 線(xiàn)程數(shù)量(1000)
        int threadCount = 1000;

        // 用來(lái)讓主線(xiàn)程等待threadCount個(gè)子線(xiàn)程執(zhí)行完畢
        CountDownLatch countDownLatch = new CountDownLatch(threadCount);

        // 啟動(dòng)threadCount個(gè)子線(xiàn)程
        for(int i = 0; i < threadCount; i++)
        {
            Thread thread = new Thread(new MyThread(counter, countDownLatch));
            thread.start();
        }

        try
        {
            // 主線(xiàn)程等待所有子線(xiàn)程執(zhí)行完成,再向下執(zhí)行
            countDownLatch.await();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        // 計(jì)數(shù)器的值
        System.out.println(counter.getCount());
    }
}

class MyThread implements Runnable
{
    private Counter counter;

    private CountDownLatch countDownLatch;

    public MyThread(Counter counter, CountDownLatch countDownLatch)
    {
        this.counter = counter;
        this.countDownLatch = countDownLatch;
    }

    public void run()
    {
        // 每個(gè)線(xiàn)程向Counter中進(jìn)行10000次累加
        for(int i = 0; i < 10000; i++)
        {
            counter.addCount();
        }

        // 完成一個(gè)子線(xiàn)程
        countDownLatch.countDown();
    }
}

class Counter
{
    private int count = 0;

    public int getCount()
    {
        return count;
    }

    public void addCount()
    {
        count++;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

上面的測(cè)試代碼中,開(kāi)啟1000個(gè)線(xiàn)程,每個(gè)線(xiàn)程對(duì)計(jì)數(shù)器進(jìn)行10000次累加,最終輸出結(jié)果應(yīng)該是10000000。

但是上面代碼中的Counter未進(jìn)行同步控制,所以非線(xiàn)程安全。

輸出結(jié)果:

9963727

9973178

9999577

9987650

9988734

9988665

9987820

9990847

9992305

9972233

稍加修改,把Counter改成線(xiàn)程安全的計(jì)數(shù)器:

class Counter
{
    private int count = 0;

    public int getCount()
    {
        return count;
    }

    public synchronized void addCount()
    {
        count++;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

上面只是在addCount()方法中加上了synchronized同步控制,就成為一個(gè)線(xiàn)程安全的計(jì)數(shù)器了。再執(zhí)行程序。

輸出結(jié)果:

10000000

10000000

10000000

10000000

10000000

10000000

10000000

10000000

10000000

10000000

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多