用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());
    }
}
时间: 2024-09-29 13:27:03

用ThreadLocal为线程生成唯一标识及实现原理的相关文章

JAVA UUID 生成唯一标识

Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Reprint it anywhere u want 需求 项目在设计表的时候,要处理并发多的一些数据,类似订单号不能重复,要保持唯一.原本以为来个时间戳,精确到毫秒应该不错了.后来觉得是错了,测试环境下很多一样的ID,不能达到唯一标识. UUID JDK API 是这么说的: "表示通用唯一标识符 (UUID) 的类. UUID 表示一个 128 位的值." 详细的说就是: "

C#生成唯一值的方法汇总

生成唯一值的方法很多,下面就不同环境下生成的唯一标识方法一一介绍,作为工作中的一次总结,有兴趣的可以自行测试: 一.在 .NET 中生成 1.直接用.NET Framework 提供的 Guid() 函数,此种方法使用非常广泛.GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的任何两台计算机都不会生成重复的 GUID 值(即保证所有机器都是唯一的).关于GUID的介绍在此不作具体熬述,想深入了解可以自行查阅MSDN.代码如下: 1 using System; 2 usi

[转]iOS设备唯一标识探讨

转自:http://www.jianshu.com/p/b83b0240bd0e iOS设备唯一标识探讨 为了统计和检测应用的使用数据,几乎每家公司都有获取唯一标识的业务需求,在iOS5以前获取唯一标识,可以获取到系统提供的方法UDID(Unique Device Identifier),后来被出于用户隐私的考虑被Apple官方禁止掉了.于是,大家开始在iOS6中使用 MAC 地址(Medium/Media Access Control) ,后来又被Apple官方在iOS7中禁止掉了.苹果及其国

ios设备唯一标识获取策略

英文原文:In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02:00:00:00:00:00. If you need to identify the device, use the identifierForVendor property of UIDevice instead. (Apps that need an identifier for

IOS获取设备唯一标识的八种方法

免责声明:本文章来源于其他博客整理 参考:http://www.2cto.com/kf/201308/237648.html 参考:http://www.2cto.com/kf/201311/255684.html 在iOS系统中,获取设备唯一标识的方法有很多: 一.UDID(Unique Device Identifier) UDID的全称是Unique Device Identifier,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成(越狱的设备通过某些工具可以改变设备的U

(转)iOS获取设备唯一标识码

文/举个栗子wow(简书作者)原文链接:http://www.jianshu.com/p/65c92cd1c0ee著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. “刷优惠券”就是刷美团或者大众这些做首单优惠的App的优惠券,它们为“首单”创造了几个制约因素,其中一个就是设备的唯一性——参加过的不能再参加,这就要获取的设备的唯一标识.这项技能一度使我在大学里吃牛排看电影不要钱.有点跑题,回到正题上.我查阅了一些资料,了解了一下iOS下是如何做到“设备标识的唯一性的”.不得不说iOS

iOS获取设备唯一标识的各种方法?IDFA、IDFV、UDID分别是什么含义?

iOS获取设备唯一标识的各种方法?IDFA.IDFV.UDID分别是什么含义? [摘要:1.UDID (Unique Device Identifier) UDID的齐称是Unique Device Identifier,望文生义,它便是苹果IOS装备的独一辨认码,它由40个字符的字母战数字构成.正在良多须要限定] 一.UDID (Unique Device Identifier) UDID的全称是Unique Device Identifier,顾名思义,它就是苹果IOS设备的唯一识别码,它由

如何生成唯一的server Id,server_id为何不能重复?

我们都知道MySQL用server-id来唯一的标识某个数据库实例,并在链式或双主复制结构中用它来避免sql语句的无限循环.这篇文章分享下我对server-id的理解,然后比较和权衡生成唯一server-id的几种方式. server_id的用途 简单说来,server_id有两个用途: 1. 用来标记binlog event的源产地,就是SQL语句最开始源自于哪里. 2. 用于IO_thread对主库binlog的过滤.如果没有设置 replicate-same-server-id=1 ,那么

C# 根据twitter的snowflake算法生成唯一ID

C# 版算法: 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Demo 8 { 9 10 /// <summary> 11 /// 根据twitter的snowflake算法生成唯一ID 12 /// snowflake算法 64 位 13 /// 0---000