1. 程式人生 > >對象的使用和共享:ThreadLocal

對象的使用和共享:ThreadLocal

優點 使用 允許 read 不可變對象 可變 講解 ger 多線程

1. 引言

在多線程環境下,使用共享對象時有四種常用策略:

  1. 線程封閉:線程封閉的對象只能由一個線程擁有,線程封閉在線程中,並且只能由這個線程修改。實現技術有==棧封閉==和 ==ThreadLocal== 類;
  2. 只讀共享:只允許讀取的且不可修改的對象可以由多個線程安全的並發訪問。不可變對象和事實不可變對象此類策略的實現技術;
  3. 保護對象:使用特定的鎖訪問對象;
  4. 線程安全的共享:在對象內部實現同步,並且只使用共有接口提供訪問對象狀態——不太理解。
2. ThreadLocal基本思想

實現線程封閉的方式之一是棧封閉,只能通過局部變量才能訪問對象,而局部變量是封閉在執行的線程中的,其他線程無法修改。另一片博文展開講解。

優點

ThreadLocal為每個使用變量的線程都存有一個獨立的副本,因此每個線程對此變量的修改都是都只是在自己工作內存而已,也沒有同步內存的時間開銷。因此也可以說棧封閉是用空間換時間和安全性。

使用場景

如果對象的分配開銷特別高或者在線程中執行的頻率特別高,則應該使用ThreadLocal。

3. 實現
主要方法
  • T iniinitialValue():初始化當前線程副本值;
  • T get():返回此線程中thread-local變量副本值,如果當前線程沒有對應副本值,則會調用iniinitialValue方法返回;
  • set(T value):設置當前線程副本值;
  • remove():移除當前線程局部變量副本值。

示例:

public class ThreadLocalDemo implements Runnable {

    private static ThreadLocal<Integer> threadLocalVal=new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 1;
        }
    };
    
    public Integer getThreadLocalVal() {
        return threadLocalVal.get();//fixme 返回的只是Integer變量的副本而已
    }

    @Override
    public void run() {
        Integer i=threadLocalVal.get();
        while(true){
            System.out.println(i++);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        new Thread(new ThreadLocalDemo()).start();
        new Thread(new ThreadLocalDemo()).start();
    }
}

對象的使用和共享:ThreadLocal