用ThreadLocal为线程生成唯一标识及实现原理

1、在多线程编程中,有时候需要自动为每个启动的线程生成一个唯一标识,这个时候,通过一个ThreadLocal变量来保存每个线程的标识是最有效、最方便的方式了。

2、ThreadLocal 实例通常是类中的私有静态字段

3、在构建ThreadLocal的时候,通过覆盖子类的方法来改写序号。从而达到为每个线程生成序号的目的。

 

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 一个多线程对象,其中有个私有变量SerialNum,用来保存该对象线程的序号 
 * @author yinchuan.chen
 *
 */
class MultiThreadObject extends Thread { 
    //线程序号变量 
    private SerialNum  serialNum; 

    public MultiThreadObject(SerialNum  serialNum) { 
        //初始化线程序号保存变量 
        this.serialNum = serialNum; 
    } 

    /** 
     * 一个示意性的多线程业务方法 
     */ 
    public void run() { 
        System.out.println("线程" + Thread.currentThread().getName() + "的序号为" + serialNum.getNextNum()); 
    } 
}

/**
 * 一个示意性的ThreadLocal实现,与JDK中ThreadLocal的API对等 
 * @author yinchuan.chen
 *
 */
class SimpleThreadLocal { 
    //一个线程Map,用来存放线程和其对应的变量副本 
    private Map threadMap = Collections.synchronizedMap(new HashMap()); 

    public void set(Object object) { 
        threadMap.put(Thread.currentThread(), object); 
    } 

    public Object get() { 
        Thread currentThread = Thread.currentThread(); 
        Object obj = threadMap.get(currentThread); 
        if (obj == null && !threadMap.containsKey(currentThread)) { 
            obj = initialValue(); 
            threadMap.put(currentThread, obj); 
        } 
        return obj; 
    } 

    public void remove() { 
        threadMap.remove(Thread.currentThread()); 
    } 

    protected Object initialValue() { 
        return null; 
    } 
}

/**
 * 线程序号标识生成工具 
 * @author yinchuan.chen
 *
 */
class SerialNum { 
    //类级别的线程编号变量,指向下一个线程的序号 
    private static Integer nextNum = 0; 
    //定义一个ThreadLocal变量,存放的是Integer类型的线程序号 
//    private static ThreadLocal<Integer> threadNo = new ThreadLocal<Integer>() { 
    private static SimpleThreadLocal threadNo = new SimpleThreadLocal() { 
        //通过匿名内部类的方式定义ThreadLocal的子类,覆盖initialValue()方法 
        public synchronized Integer initialValue() { 
            return nextNum++; 
        } 
    }; 

    /** 
     * 获取线程序号 
     * 
     * @return 线程序号 
     */ 
    public int getNextNum() { 
        return (Integer)threadNo.get(); 
    } 
}


public class TestTreadLocal { 
    public static void main(String[] args) { 
        SerialNum serialNum = new SerialNum(); 
        MultiThreadObject m1 = new MultiThreadObject(serialNum); 
        MultiThreadObject m2 = new MultiThreadObject(serialNum); 
        MultiThreadObject m3 = new MultiThreadObject(serialNum); 
        MultiThreadObject m4 = new MultiThreadObject(serialNum); 

        m1.start(); 
        m2.start(); 
        m3.start(); 
        m4.start(); 

        //下面的test方法是在主线程中,当前线程是 
        testMainThread(); 
    } 

    public static void testMainThread(){ 
        SerialNum serialNum = new SerialNum(); 
        System.out.println("主线程的序号为"+serialNum.getNextNum()); 
        SerialNum serialNum2 = new SerialNum(); 
        System.out.println("主线程的序号为"+serialNum2.getNextNum()); 
    } 
}

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。