关于ThreadLocal的一点理解

来源:互联网 发布:b2b软件有哪些 编辑:程序博客网 时间:2024/05/21 06:59

这个问题困扰了自己挺久,知道在知乎上看到一个大神的回答,顿时有种拨开云雾见青天的感觉。
https://www.zhihu.com/question/23089780
在前人的基础上再次稍加总结,以加深印象。

ThreadLocal并不是为了解决并发访问数据过程中可能存在的数据不一致问题,事实上ThreadLocal是为了解决变量在线程内部各个方法之间共享的问题。

class TestGoWan implements Runnable{    private int id;    public TestGoWan(int id) {        super();        this.id = id;    }    private static ThreadLocal<GongJiaoCard> tl = new ThreadLocal<GongJiaoCard>();    public void run() {        GongJiaoCard g = new GongJiaoCard((int)(Math.random()*100));        tl.set(g);        this.goByBus();        this.goByMetro();    }    public void goByBus(){        System.out.println("线程id"+id+"拿着公交卡id:"+tl.get().getId()+"坐公交!");    }    public void goByMetro(){        System.out.println("线程id"+id+"拿着公交卡id:"+tl.get().getId()+"坐地铁!");    }}class GongJiaoCard{    private int id;    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public GongJiaoCard(int id) {        super();        this.id = id;    }}public class TestThread{    public static void main(String[] args) {        for(int i = 1; i<6; i++){            Thread t = new Thread(new TestGoWan(i));            t.start();        }    }}

代码运行结果如下:

线程id4拿着公交卡id:56坐公交!线程id2拿着公交卡id:14坐公交!线程id2拿着公交卡id:14坐地铁!线程id3拿着公交卡id:36坐公交!线程id5拿着公交卡id:37坐公交!线程id1拿着公交卡id:48坐公交!线程id5拿着公交卡id:37坐地铁!线程id3拿着公交卡id:36坐地铁!线程id4拿着公交卡id:56坐地铁!线程id1拿着公交卡id:48坐地铁!

可以看到每个线程拿的都是自己的公交卡,也就是说ThreadLocal中保存的变量在同一线程的不同方法(goByBus、goByMetro)之间可以共享,但是在不同的线程之间是隔离的。

要想实现变量在同一线程的不同方法之间共享,而在线程之间隔离貌似用如下方式也可以

class TestGoHaveFun  implements Runnable{    private int id;    private GongJiaoCard g;    public TestGoHaveFun(int id) {        super();        this.id = id;    }    public void run() {        g = new GongJiaoCard((int)(Math.random()*100));        goByBus();        goByMetro();    }    public void goByBus(){        System.out.println("线程id"+id+"拿着公交卡id:"+g.getId()+"坐公交!");    }    public void goByMetro(){        System.out.println("线程id"+id+"拿着公交卡id:"+g.getId()+"坐地铁!");    }   }

这个问题暂且放下,待哪天真正弄明白再来补充。

接下来分析从ThreadLocal源码的角度分析下其实现原理。

先从ThreadLocal核心的set和get方法开始:

public void set(T value) {        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null)            map.set(this, value);        else            createMap(t, value);    }

它先拿到当前线程,并获得当前线程的的ThreadLocalMap的变量,这个ThreadLocalMap是ThreadLocal的内部类。拿到这个map后,以当前的 ThreadLocal对象为键,参数value为值将此键值对保存到此map中。这样,由于这个ThreadLocalMap是通过当前线程获取的,那么保存在该map中的键值对就是当前线程相关的。

原创粉丝点击