八、ThreadLocal

先看示例:

public class ThreadTest{

    private static int num1 = 0;
    @Test
    public void m1(){
        for(int i = 0 ;i<2;i++){
            new Thread(new Runnable(){
                @Override
                public void run() {
                    num1= new Random().nextInt();
                    System.out.println(Thread.currentThread().getName()+": data : "+num1);
                    new A();
                }
            }).start();
        }
    }
    
    class A{
        public A() {
            System.out.println("A :"+Thread.currentThread().getName()+" data : "+num1);
        }
    }
    

}

上面示例中,定义了一个类变量num1,创建两个线程分别给num1赋随机值然后打印,在内部类A中也对num1的值进行打印。整个过程中,变量num1为所有线程所共享,只要有一个线程将其值改变,其它线程的值也会跟着改变。那么问题就来了,在很多时候,我们在一个线程中处理的数据,仅希望它在当前线程中有效,而不受其它线程的影响。也就是说,数据仅在当前线程中传播。那么,该如何实现呢?

public class ThreadTest {
    /**
     * 当以一个map,用来存储当前线程的数据
     */
    private static Map<Thread,Integer> map = new HashMap<Thread,Integer>();
    @Test
    public void m2(){
        for(int i = 0 ;i<2;i++){
            new Thread(new Runnable(){
                @Override
                public void run() {
                    int num2 = new Random().nextInt();
                    map.put(Thread.currentThread(), num2);  //将值绑定到当前线程中。
                    System.out.println(Thread.currentThread().getName()+": data : "+num2);
                    new B();
                }
            }).start();
        }
    }
    class B{
        public B() {
            int num2 = map.get(Thread.currentThread());  //取出当前线程的共享变量
            System.out.println("B :"+Thread.currentThread().getName()+" data : "+num2);
        }
    }

}

上面的示例中,已经实现了在线程的范围内共享。但是,灵活性不足。在lang包下已经为我们实现了线程局部变量的类ThreadLocal。

public class ThreadLocal {
    /**
     * 创建一个线程局部变量
     */
    private static ThreadLocal<Integer> local = new ThreadLocal<Integer>();
    @Test
    public void m3(){
        for(int i = 0 ;i<2;i++){
            new Thread(new Runnable(){
                @Override
                public void run() {
                    int num3 = new Random().nextInt();
                    local.set(num3);  //线程局部变量赋值。
                    System.out.println(Thread.currentThread().getName()+": data : "+num3);
                    new C();
                }
            }).start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    class C{
        public C() {
            int num3 = local.get();  //取出当前线程的局部变量
            System.out.println("C :"+Thread.currentThread().getName()+" data : "+num3);
        }
    }

}

版本四:这样写的好处自己体会。

public class ThreadLocalTest2 {
        @Test
    public void m4(){
        for(int i = 0 ;i<5;i++){
            new Thread(new Runnable(){
                @Override
                public void run() {
                    int num4 = new Random().nextInt();
                    System.out.println(Thread.currentThread().getName()+": data : "+num4);
                    D d = D.getD();
                    d.setData(num4);
                    d.printD();
                }
            }).start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

/**
 * 将线程局部变量封装到一个类里面
 */
class D{
    private static ThreadLocal<D> current= new ThreadLocal<D>();
    
    private int data;
    
    private D(){}
    
    public static D getD(){
        if(current.get() == null){
            current.set(new D());
        }
        return current.get();
    }
    
    public int getData() {
        return data;
    }
    public void setData(int data) {
        this.data = data;
    }
    
    public void printD(){
        System.out.println(Thread.currentThread()+": D : data:"+data);
    }
}
原文地址:https://www.cnblogs.com/futiansu/p/5616001.html