线程副本

Posted by 小白 on December 18, 2016

线程副本为每个使用该变量的线程提供一个独立的变量副本,即多个线程操作同一个变量,互相不会影响对方的值。

  • void set()设置当前线程的线程副本的值
  • public T get()返回当前线程拥有的线程副本的值
  • public void remove()将该线程的线程副本的值删除。需要注意的是该方法不是一定要显式调用的,当线程结束后,Java的垃圾回收机制也会起作用,但是显式调用可以加快内存的回收。
  • protected T initialValue()返回该线程的线程副本的初始值。

直接看代码:

package com.server.example.util.thread.basic;

/**
 * Created by Administrator on 2016/12/18.
 * 线程副本的示例
 */
public class ThreadLocalDemo {
    //通过匿名内部类的方式覆盖ThreadLocal的initialValue方法
    private static ThreadLocal<Integer> num=new ThreadLocal<Integer>(){
        @Override
        public Integer initialValue(){
            return 0;
        }
    };

    public ThreadLocal<Integer> getThreadLocal(){
        return num;
    }

    public int getNextNum(){
        num.set(num.get()+1);//在这里对线程副本做递增操作
        return num.get();
    }

    public static class TestClient extends Thread{
        private ThreadLocalDemo threadLocalDemo;
        public TestClient(ThreadLocalDemo threadLocalDemo){
            this.threadLocalDemo=threadLocalDemo;
        }

        @Override
        public void run(){
            for (int i=0;i<3;i++){
                System.out.println("thread["+Thread.currentThread().getName()+"]-->threadLocalDemo["+threadLocalDemo.getNextNum()+"]");
            }
            threadLocalDemo.getThreadLocal().remove();//每次使用完要删除线程副本,否则容易造成内存泄漏
        }
    }

    public static void main(String[] args){
        ThreadLocalDemo threadLocalDemo=new ThreadLocalDemo();
        TestClient t1=new TestClient(threadLocalDemo);
        TestClient t2=new TestClient(threadLocalDemo);
        TestClient t3=new TestClient(threadLocalDemo);
        t1.start();
        t2.start();
        t3.start();
    }
}

ThreadLocal比synchronized同步机制解决线程安全问题更简单更方便,且拥有更高的并发性。

需注意:使用ThreadLocal,一般都是声明在静态变量中,如果不断地创建且不remove,将会导致内存泄漏,尤其是在高并发的web容器中。