轻松突击ThreadLocal

原创 2016年08月28日 16:46:25

本文出自
代码大湿
代码大湿

ThreadLocal是用来保存线程的本地变量,可以保证每个线程都有一个自己的变量(包括static变量)。

本文所有代码请点击我

1 看个实际场景。

我们要设计一个序列号生成器,每个线程之间对序列号的获取是是隔离的。初始我们可能会这样设计。使用一个static变量。

首先有一个序列号生成器的接口

package ThreadLocal;
/*
 *2016年8月28日    下午2:48:17
 *@Author Pin-Wang
 *@E-mail 1228935432@qq.com
*/
public interface NumberConstruct {
    public int get();
}

生成器的具体实现是:

package ThreadLocal;
/*
 *2016年8月28日    下午2:49:34
 *@Author Pin-Wang
 *@E-mail 1228935432@qq.com
*/
public class ConcreteNumberConstructA implements NumberConstruct{
    private volatile static int n=0;
    @Override
    public  synchronized int get() {
        return ++n;
    }
}

客户端:

package ThreadLocal;

/*
 *2016年8月28日    下午2:46:10
 *@Author Pin-Wang
 *@E-mail 1228935432@qq.com
*/
public class Test {
    //不使用ThreadLocal
    private static NumberConstruct numberConstruct=new ConcreteNumberConstructA();;

    //使用ThreadLocal
    //private static NumberConstruct numberConstruct=new ConcreteNumberConstructB();;

    public static void main(String[] args){
        //每个线程获取三个序列号
        Runnable task=new Runnable() {
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println(Thread.currentThread().getName()+" "+numberConstruct.get());
                }
            }
        };
        //开启是哪个线程
        Thread t1=new Thread(task);
        Thread t2=new Thread(task);
        Thread t3=new Thread(task);
        t1.start();
        t2.start();
        t3.start();
    }

}

结果;

这里写图片描述

可以看到3个线程之间都共享了static变量(没有考虑到共享资源的线程安全),这并不是我们想要的结果。

所以我们用ThreadLocal解决:

生成器的具体实现:

package ThreadLocal;
/*
 *2016年8月28日    下午2:49:34
 *@Author Pin-Wang
 *@E-mail 1228935432@qq.com
*/
public class ConcreteNumberConstructB implements NumberConstruct{
    private  static ThreadLocal<Integer> n=new ThreadLocal<Integer>(){

        @Override
        protected Integer initialValue() {
            return 0;
        }};


    @Override
    public   int get() {
        n.set(n.get()+1);
        return n.get();
    }
}

客户端中将

//不使用ThreadLocal
private static NumberConstruct numberConstruct=new ConcreteNumberConstructA();

替换为

//使用ThreadLocal
private static NumberConstruct numberConstruct=new ConcreteNumberConstructB();

其它均不变

结果:
这里写图片描述

这是我们想要的结果。可以看到对于每个共享变量,每个线程之间都有自己的副本,线程之间是隔离的。

2 实现我们自己的ThreadLocal。

ThreadLocal内部其实非常简单。主要是一个同步的HashMap(因为涉及到多线程共享资源),主要有以下几个方法;

//得到当前线程的副本值
get()

//设定当前线程的副本值
set()

//删除当前线程的副本值
remove()

//初始化当前线程的副本值
initialValue()

code;

MyThreadLocal类

package ThreadLocal;
/*
 *2016年8月28日    下午3:57:17
 *@Author Pin-Wang
 *@E-mail 1228935432@qq.com
*/

import java.util.concurrent.ConcurrentHashMap;

public class MyThreadLocal<T> {
    private ConcurrentHashMap<Thread, T> map=new ConcurrentHashMap<>();
    //initialValue()
    protected T initialValue(){
        //返回null,由子类指定初始值
        return null;
    }

    //set()
    public void set(T value){
        map.put(Thread.currentThread(), value);
    }
    //get()
    public T get(){
        if(!map.containsKey(Thread.currentThread())){
            T value=initialValue();
            map.put(Thread.currentThread(), value);
        }
        return map.get(Thread.currentThread());
    }
    //remove()
    public void remove(){
        map.remove(Thread.currentThread());
    }

}

ConcreteNumberConstructC 类

package ThreadLocal;
/*
 *2016年8月28日    下午2:49:34
 *@Author Pin-Wang
 *@E-mail 1228935432@qq.com
*/
public class ConcreteNumberConstructC implements NumberConstruct{
    private   MyThreadLocal<Integer> n=new MyThreadLocal<Integer>(){

        @Override
        protected Integer initialValue() {
            return 0;
        }};


    @Override
    public   int get() {
        n.set(n.get()+1);
        return n.get();
    }
}

将客户端中的

//使用ThreadLocal
private static NumberConstruct numberConstruct=new ConcreteNumberConstructB();

替换为

//使用自己的MyThreadLocal
private static NumberConstruct numberConstruct=new ConcreteNumberConstructC();

结果:

这里写图片描述

总结:如果你需要多个线程之间共享变量的时候,想下是否需要考虑线程安全的问题,如果需要则可以使用ThreadLocal简单解决。

本文出自
代码大湿
代码大湿

版权声明:本文为博主原创文章,未经博主允许不得转载。

ThreadLocal简单Demo

  • 2017年10月17日 14:58
  • 131KB
  • 下载

孙俪突击入股海润影视折射啥弊端?

近日,申科股份(002633,前收盘价9.29元)突然宣布,将持有海润影视100%股权。这就意味着,公司主营业务由滑动轴承生产销售转变为电视剧制作发行,公司实际控制人变更为海润影视大股东刘燕铭。值得一...

《士兵突击》

因为华夏上下5000年的悠久沉重历史,所以国内的电视剧题材比较多,但是军旅题材一直是我钟爱的。 以前小学和初中总喜欢看有意思和好笑的动画片,也领悟不到多少内涵,只是一笑而过,逗乐而已...
  • gogoky
  • gogoky
  • 2013年07月20日 10:36
  • 849

【codevs2950】突击考试

一朵孤芳自赏的花只是美丽,一片相依恃着而怒放的锦绣才是灿烂。

看《士兵突击》有感~~

只要今天比昨天好,这不就是希望么? 要时刻对自己说,我能行

无中生有之突击NOIP(8)——更多算法(一)

又开始了哈: 最小生成树(1) 何为最小生成树呢?我们有很多路可以选,可有有很多种方案,然而如何达到一个最低值,而取消掉那些多余的路呢?这就是它的作用所在! 算法分析: 首先我们要让n个顶...

无中生有之突击NOIP(4)--搜索

1、深度优先搜索 定义:从起始点一条道走到黑,到头没路了,就退一步,看看有没有路,有路继续走到黑,没路就再退一步。退退退……引子例题:我们经过n个盒子,并且每个里面放入我们手中的n张不同的牌,共有多...

Codeforces 546C Soldier and Cards【模拟】【期末考试全突击啊T T 】

C. Soldier and Cards time limit per test 2 seconds memory limit per test 256 megabytes ...

Theano快速突击(一)

1. Theano的发音 第一次碰到时很自然的发音是 /θi.ˈæ.noʊ/,不过如果看一些视频可能也有发/te.ˈaː.no/的。这两种都有,比较官方的说法可能是这个: I think I say ...

直板正胶技术:下旋球突击的要点

最近看到好多正胶球友在探讨正胶的下旋球突击技术,虽然在个别帖子里,我做了一些个人体会的回复,但是考虑到方便球友,服务球友的宗旨,现将个人关于下旋球突击的体会整理一下单发。供各位正胶球友交流、批评、指正...
  • lzy_168
  • lzy_168
  • 2013年05月03日 16:35
  • 1683
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:轻松突击ThreadLocal
举报原因:
原因补充:

(最多只允许输入30个字)