zoukankan      html  css  js  c++  java
  • 理解ThreadLocal

    ThreadLocal是什么

    早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。

    ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。

    当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

    从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。

    线程局部变量并不是Java的新发明,很多语言(如IBM IBM XL FORTRAN)在语法层面就提供线程局部变量。在Java中没有提供在语言级支持,而是变相地通过ThreadLocal的类提供支持。

    所以,在Java中编写线程局部变量的代码相对来说要笨拙一些,因此造成线程局部变量没有在Java开发者中得到很好的普及。

    ThreadLocal的接口方法

    ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:

    • void set(Object value)

    设置当前线程的线程局部变量的值。

    • public Object get()

    该方法返回当前线程所对应的线程局部变量。

    • public void remove()

    将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

    • protected Object initialValue()

    返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。

    值得一提的是,在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal<T>。API方法 也相应进行了调整,新版本的API方法分别是void set(T value)、T get()以及T initialValue()。

    代码示例:

    两个对象:

    普通的对象

    package basic.threadLocal;
    
    /**
     * Created with IntelliJ IDEA.
     * User: yfwangqing
     * Date: 13-7-26
     * Time: 上午8:49
     * To change this template use File | Settings | File Templates.
     */
    public class Mybean {
        private int num;
    
        public int getNum() {
            return num;
        }
    
        public void add(int num) {
            this.num++;
        }
    }

    使用ThreadLocal的对象

    package basic.threadLocal;
    
    /**
     * Created with IntelliJ IDEA.
     * User: yfwangqing
     * Date: 13-7-26
     * Time: 上午8:50
     * To change this template use File | Settings | File Templates.
     */
    public class MySafeBean {
        private ThreadLocal<Integer> localCount = new ThreadLocal<Integer>() {
            protected Integer initialValue() {
                return 0;
            }
        };
    
        public Integer getNum() {
            return localCount.get();
        }
    
        public void add(Integer num) {
            int count = localCount.get();
            count++;
            this.localCount.set(count);
        }
    }

    测试代码:

    package basic.threadLocal;
    
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    /**
     * Created with IntelliJ IDEA.
     * User: yfwangqing
     * Date: 13-7-26
     * Time: 上午8:57
     * To change this template use File | Settings | File Templates.
     */
    public class ThreadLocalTest {
        private Mybean mybean;
        private MySafeBean mySafeBean;
        private Thread my1;
        private Thread my2;
        private Thread mySafe1;
        private Thread mySafe2;
    
        @Before
        public void setUp() throws Exception {
            mybean = new Mybean();
            mySafeBean = new MySafeBean();
            my1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        mybean.add(i);
                    }
                    System.out.println("m1:" + mybean.getNum());
                }
            });
            my2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 50; i++) {
                        mybean.add(i);
                    }
                    System.out.println("m2:" + mybean.getNum());
                }
            });
            mySafe1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        mySafeBean.add(i);
                    }
                    System.out.println("s1:" + mySafeBean.getNum());
                }
            });
            mySafe2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 50; i++) {
                        mySafeBean.add(i);
                    }
                    System.out.println("s2:" + mySafeBean.getNum());
                }
            });
    
        }
    
        @After
        public void tearDown() throws Exception {
    
        }
    
        @Test
        public void test() throws Exception {
            my1.start(); //不定值
            my2.start(); //不定值
            mySafe1.start(); //始终输出100
            mySafe2.start(); //始终输出50
        }
    }

     对象回收方面:每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。

    概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。所以在性能上ThreadLocal要优于同步方式。

    总结:

    ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。
     
    ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
     
    ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区 别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本, 使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通 信时能够获得数据共享。
     
    Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
     
    当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。
  • 相关阅读:
    R语言:提取路径中的文件名字符串(basename函数)
    课程一(Neural Networks and Deep Learning),第三周(Shallow neural networks)—— 0、学习目标
    numpy.squeeze()的用法
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 4、Logistic Regression with a Neural Network mindset
    Python numpy 中 keepdims 的含义
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 3、Python Basics with numpy (optional)
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 2、编程作业常见问题与答案(Programming Assignment FAQ)
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 0、学习目标
    课程一(Neural Networks and Deep Learning),第一周(Introduction to Deep Learning)—— 0、学习目标
    windows系统numpy的下载与安装教程
  • 原文地址:https://www.cnblogs.com/zhishan/p/3216361.html
Copyright © 2011-2022 走看看