轻松突击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简单解决。

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

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

UVA 11729 突击战

这道题一样简单,使用贪心即可。这一小节都只需用贪心,加油吧!
  • cnyali_ljf
  • cnyali_ljf
  • 2016年04月25日 21:36
  • 888

《艺术人生:士兵突击》专访中震撼心灵的几段话

昨晚和今天看了《艺术人生:士兵突击》专访,采访了几位主要演员和导演、编剧,采访过程中各位嘉宾的即兴回答很精彩,其中有几段话特别让我感动,于是整理出来和大家共勉! 陈思成: ——面对挫折的选择 1、我觉...
  • chenyusiyuan
  • chenyusiyuan
  • 2008年01月04日 15:36
  • 2533

UVA11729突击战(汇报和执行任务)

题意:       你是一个长官,有一些士兵要跟你先汇报任务后在去执行任务,每次只能接受一个人的汇报,但是每一时刻可以有多个士兵在执行任务,问所有任务执行完要的最小时间。 思路:    ...
  • u013761036
  • u013761036
  • 2014年10月16日 09:31
  • 294

《实战突击:Java Web项目整合开发》简介及源码

本书以都市供求信息网、物流配货网、编程爱好者博客地带、明日知道、天下淘网络商城、成长在线考试网、企业物资管理系统、办公自动化管理系统、校园管理系统、高校学生选课系统、网络购物中心、博研图书馆管理系统、...
  • HanTangSongMing
  • HanTangSongMing
  • 2014年04月24日 18:58
  • 12729

突击战【JAVA算法实现】

题目描述 在你的王国里有一条n个头的恶龙,你希望雇一些骑士把它杀死(即砍掉所有头)。村里有m个骑士可以雇佣,一个能力值为m的骑士可以砍掉一个直径不超过x的头,且需要支付x个金币。如何雇佣骑士才能砍掉...
  • u011028655
  • u011028655
  • 2014年11月18日 11:46
  • 655

uva11729突击战!!!

第一次写博客啊,以前一直发在qq空间里面防毒,真的很不好,伟大的唐老师和chc告诉我应该写博客,那就来吧。 怎么说呢?这道题的思路很简单,但是就是实现的出了一点问题,我一开始想用一个rest的指针来...
  • zsd201531107026
  • zsd201531107026
  • 2016年08月08日 15:54
  • 133

转战c++

 从c->java->c++   都是由于项目的需要,最近做的数据采集服务,本来考虑用Java也行,但是由于是服务端的考虑用c++开发,这样增加项目的风险,主要原因是以前用c++没有做过项目。算是自我...
  • ahg1001
  • ahg1001
  • 2010年05月28日 09:53
  • 360

贪心-突击战(Commando War, UVa 11729)

题目:你有n个部下,每个部下需要完成一项任务。第i个部下需要你花Bi分钟交待任务,然后他会立刻独立地、无间断地执行Ji分钟后完成任务。你需要选择交待任务的顺序,使得所有任务尽早执行完毕(即最后一个执行...
  • Double2hao
  • Double2hao
  • 2016年06月22日 09:28
  • 1250

看《士兵突击》有感~~

只要今天比昨天好,这不就是希望么? 要时刻对自己说,我能行
  • qq_27709465
  • qq_27709465
  • 2015年07月09日 20:36
  • 280

算法竞赛入门经典 突击战

算法竞赛入门经典 突击战 /* Name: 突击战 Copyright: 刘汝佳 Author: Analyst Date: 27/02/14 23:59 Description...
  • u013055228
  • u013055228
  • 2014年03月01日 10:01
  • 956
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:轻松突击ThreadLocal
举报原因:
原因补充:

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