【java】【併發編程】線程封閉

線程封閉

當訪問共享的可變數據時,通常需要使用同步。一種避免使用同步的方式就是不共享數據。如果僅在單線程內訪問數據,就不需要同步。這種技術被稱爲線程封閉

棧封閉

局部變量的固有屬性之一就是封閉在線程中。它們位於執行線程的棧中,其他線程無法訪問這個棧。

public int loadTheArk(Collection<Animal> candidates){
    SortedSet<Animal> animals;
    int numPairs = 0;
    Animal candidates = null;
    //animals被封閉在方法中,不要使它們逸出
    animals = new TreeSet<Animal>(new SpeciesGenderComparator());
    animals.addAll(candidates);
    for (Animal a : animals) {
        if (candidates == null || !candidates.isPotentialMate(a)) {
            candidates = a;
        } else {
            ark.load(new AnimalPair(candidates,a));
            ++numPairs;
            candidates = null;
        }
    }
    return numPairs;
}

如上例子,我們將animals封閉在方法中,使得它在每個線程都是獨有的,而不是共享的。

ThreadLocal類

ThreadLocal類爲每一個使用該變量的線程都提供一個變量值的副本,是Java中一種較爲特殊的綁定機制,是每一個線程都可以獨立地改變自己的副本,而不會與其他副本衝突。

  • ThreadLocal如何爲每一個線程維護變量的副本?
    在ThreadLocal類中有一個Map,用於存儲每一個線程的變量的副本。

  • 對於多線程資源問題,同步機制採用了“以時間換空間”的方式,而ThreadLocal採用了“以空間換時間”的方式。前者僅提供了一份變量,讓不同的線程排隊訪問,而後者爲每一個線程都提供了一份變量,因此可以同時訪問而互不影響。

public class TestNum {
    //初始化
    private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){
        public Integer initialValue() {
            return 0;
        }
    };

    public int getNextNum(){
        seqNum.set(seqNum.get()+1);
        return seqNum.get();
    }

    public static void main(String[] args) {
        TestNum sn = new TestNum();

        //三個線程共享SN 產生序列號
        ThreadClient t1 = new ThreadClient(sn);
        ThreadClient t2 = new ThreadClient(sn);
        ThreadClient t3 = new ThreadClient(sn);
        t1.start();
        t2.start();
        t3.start();
    }
}

class ThreadClient extends Thread{
    private TestNum sn ;

    public ThreadClient(TestNum sn){
        this.sn = sn;
    }
    public void run(){
        for(int i = 0 ; i < 3 ; i++){
            System.out.println("Thread: "+ Thread.currentThread().getName()
                    + " sn: " + sn.getNextNum());
        }
    }
}

運行結果:
Thread: Thread-1 sn: 1
Thread: Thread-0 sn: 1
Thread: Thread-2 sn: 1
Thread: Thread-2 sn: 2
Thread: Thread-0 sn: 2
Thread: Thread-1 sn: 2
Thread: Thread-1 sn: 3
Thread: Thread-0 sn: 3
Thread: Thread-2 sn: 3

如上,我們可以看到三個線程之間的數據都是相互獨立的。

再比如在多個線程對連接數據庫的操作時:

private static ThreadLocal<Connection> connectionHolder 
    = new ThreadLocal<Connection>(){
        public Connection initialValue(){
            return DriverManager.getConnection(DB_URL);
        }
    };

public static Connection getConnection(){
    return connectionHolder.get();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章