(Java多线程系列八)ThreadLocal

ThreadLocal

1、什么是ThreadLocal

ThreadLocal是保存线程本地化对象的容器,当运行于多线程环境的某个对象用ThreadLocal维护变量时,ThreadLocal为每个使用变量的线程分配一个独立的变量副本。所以每个线程都可以独立的改变自己的副本,而不会影响其他线程所对应的副本。

从线程的角度看,这个变量就像线程专有的本地变量,这也是类名中"Local"所要表达的意思。

2、一个ThreadLocal的示例

class Entity {
    // 使用重写initialValue方法初始化值
//    public ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
//        @Override
//        protected Integer initialValue() {
//            return 0;
//        }
//    };

    // 使用lambda表达式初始化值
    public ThreadLocal<Integer> seqNum = ThreadLocal.withInitial(() -> 0);

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


class ThreadDemo extends Thread {

    private Entity entity;

    public ThreadDemo(Entity entity) {
        this.entity = entity;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(getName() + "=====" + entity.getNextSeqNum());
        }
    }
}

public class ThreadLocalDemo {
    public static void main(String[] args) {
        Entity entity = new Entity();
        ThreadDemo threadDemo01 = new ThreadDemo(entity);
        ThreadDemo threadDemo02 = new ThreadDemo(entity);
        threadDemo01.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadDemo02.start();
    }
}

3、实现个简单的ThreadLocal

public class SimpleThreadLocal<T> {

    private Map<Thread, T> map = Collections.synchronizedMap(new HashMap<>());

    public void set(T val) {
        map.put(Thread.currentThread(), val);
    }

    public T get() {
        Thread thread = Thread.currentThread();
        if (map.containsKey(thread)) {
            return map.get(thread);
        } else {
            T t = init();
            map.put(thread, t);
            return t;
        }
    }

    public void remove() {
        map.remove(Thread.currentThread());
    }

    public T init() {
        return null;
    }

}

下面我们调用自己实现的ThreadLocal测试效果

class Entity01 {

    public SimpleThreadLocal<Integer> seqNum = new SimpleThreadLocal<Integer>() {
        @Override
        public Integer init() {
            return 0;
        }
    };

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


class ThreadDemo01 extends Thread {

    private Entity01 entity;

    public ThreadDemo01(Entity01 entity) {
        this.entity = entity;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(getName() + "=====" + entity.getNextSeqNum());
        }
    }
}

public class SimpleThreadLocalDemo {
    public static void main(String[] args) {
        Entity01 entity = new Entity01();
        ThreadDemo01 threadDemo01 = new ThreadDemo01(entity);
        ThreadDemo01 threadDemo02 = new ThreadDemo01(entity);
        threadDemo01.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadDemo02.start();
    }
}

可以看到实现了同样的效果

4、ThreadLocal与Thread同步机制的比较

对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式:访问串行化,对象共享化

ThreadLocal采用了“以空间换时间”的方式:访问并行化,对象共享化

前者仅提供了一份变量,让不同的线程排队访问;而后者为每个线程都提供了一份变量,因此可以同时访问而互不影响。

源码地址

posted @ 2019-12-26 09:21  3LittleStones  阅读(207)  评论(0编辑  收藏  举报