zoukankan      html  css  js  c++  java
  • Java ThreadLocal的使用

    1.ThreadLocal用来解决多线程程序的并发问题
    2.ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都
    可以独立地改变自己的副本,而不会影响其它线程所对应的副本.
    3.从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。
    4.线程局部变量并不是Java的新发明,Java没有提供在语言级支持(语法上),而是变相地通过ThreadLocal的类提供支持.
    5.ThreadLocal类中的方法:(JDK5版本之后支持泛型)
    void set(T value)
    将此线程局部变量的当前线程副本中的值设置为指定值
    void remove()
    移除此线程局部变量当前线程的值
    protected T initialValue()
    返回此线程局部变量的当前线程的“初始值”
    T get()
    返回此线程局部变量的当前线程副本中的值
    6.ThreadLocal的原理:
    ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素
    的键为线程对象,而值对应线程的变量副本
    7.自己模拟ThreadLocal:

    public class SimpleThreadLocal{
    private Map valueMap=Collections.synchronizedMap(new HashMap());
    public void set(Object newValue){
    valueMap.put(Thread.currentThread(),newValue);//键为线程对象,值为本线程的变量副本
    }
    public Object get(){
    Thread currentThread=Thread.currentThread();
    Object o=valueMap.get(currentThread);//返回本线程对应的变量
    if(o==null&&!valueMap.containsKey(currentThread)){
    //如果在Map中不存在,放到Map中保存起来
    o=initialValue();
    valueMap.put(currentThread,o);
    }
    return o;
    }
    public void remove(){
    valueMap.remove(Thread.currentThread());
    }
    public void initialValue(){
    return null;
    }
    }


    8.使用ThreadLocal的具体例子:

    public class SequenceNumber{
    //通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
    private static ThreadLocal<Integer> seNum=new ThreadLocal<Integer>(){
    protected Integer initialValue(){
    return 0;
    }
    }
    public Integer getNextNum(){
    seNum.set(seNum.get()+1);
    return seNum.get();
    }
    public static void main(String[] args){
    SequenceNumber sn=new SequenceNumber();
    //3个线程共享sn,各自产生序列号
    TestClient t1 = new TestClient(sn);
    TestClient t2 = new TestClient(sn);
    TestClient t3 = new TestClient(sn);
    t1.start();
    t2.start();
    t3.start();
    }
    private static class TestClient extends Thread{
    private SequenceNumber sn;
    public TestClient(SequenceNumber sn){
    this.sn=sn;
    }
    public void run(){
    //每个线程打印3个序列号
    for(int i=0;i<3;i++){
    System.out.println("thread["+Thread.currentThread().getName()+",sn["+sn.getNextNum()+"]");
    }
    }
    }
    }

    9.下面是一个完整的可执行的ThreadLocal例子:

           public class ThreadLocalExample {
            public static class MyRunnable implements Runnable {
                private ThreadLocal threadLocal = new ThreadLocal();
                @Override
                public void run() {
                    threadLocal.set((int) (Math.random() * 100D));
                    try {
                    Thread.sleep(2000);
                    } catch (InterruptedException e) {
                    }
                    System.out.println(threadLocal.get());
                }
            }
            public static void main(String[] args) {
                 MyRunnable sharedRunnableInstance = new MyRunnable();
                 Thread thread1 = new Thread(sharedRunnableInstance);
                 Thread thread2 = new Thread(sharedRunnableInstance);
                 thread1.start();
                 thread2.start();
            }
        }

    上面的例子创建了一个MyRunnable实例,并将该实例作为参数传递给两个线程。两个线程分别执行run()方法,并且都在ThreadLocal实例上保存了不同的值。如果它们访问的不是ThreadLocal对象并且调用的set()方法被同步了,则第二个线程会覆盖掉第一个线程设置的值。但是,由于它们访问的是一个ThreadLocal对象,因此这两个线程都无法看到对方保存的值。也就是说,它们存取的是两个不同的值。

  • 相关阅读:
    P2569 [SCOI2010]股票交易
    P1963 [NOI2009]变换序列
    My thoughts after NOIP 2018(2)
    洛谷 P3159(BZOJ 2668)[CQOI2012]交换棋子
    My thoughts after NOIP 2018(1)
    洛谷【P1523】旅行商的背包(算法导论 15-1) 题解
    洛谷【P2458】[SDOI2006]保安站岗 题解 树上DP
    【BLUESKY的NOIp模拟赛】解题报告
    bzoj4400
    luogu2034
  • 原文地址:https://www.cnblogs.com/zjm-1/p/9045396.html
Copyright © 2011-2022 走看看