说到可继承的线程变量,大家可能会想到jdk里的实现java.lang.InheritableThreadLocal。它拥有和线程变量ThreadLocal一样的功能,并且,在当前线程上创建一个新的线程实例Thread时,会把这些线程变量从当前线程传递给新的线程实例。(此时线程变量不再线程安全,需要考虑线程安全问题)
InheritableThreadLocal:
public class InheritableThreadLocal<T> extends ThreadLocal<T> { /** * Computes the child's initial value for this inheritable thread-local * variable as a function of the parent's value at the time the child * thread is created. This method is called from within the parent * thread before the child is started. * <p> * This method merely returns its input argument, and should be overridden * if a different behavior is desired. * * @param parentValue the parent thread's value * @return the child thread's initial value */ protected T childValue(T parentValue) { return parentValue; } /** * Get the map associated with a ThreadLocal. * * @param t the current thread */ ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; } /** * Create the map associated with a ThreadLocal. * * @param t the current thread * @param firstValue value for the initial entry of the table. * @param map the map to store. */ void createMap(Thread t, T firstValue) { t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue); } }
该类继承了ThreadLocal并重写了和ThreadLocalMap相关的方法。这个ThreadLocalMap其实是java线程对象Thread类的两个属性
class Thread implements Runnable { ....... /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null; /* * InheritableThreadLocal values pertaining to this thread. This map is * maintained by the InheritableThreadLocal class. */ ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; ........ }
这两个ThreadLocalMap其实就是线程变量实际存放的地方,我们用了线程变量set内容,其实就是往ThreadLocalMap里put内容,key是你定义的ThreadLocal本身,value是你往线程变量set的内容。因为内容是存在线程本身上,所以,同一个线程跨了多少个方法都可以访问到,不同线程就访问不到或访问到不同的对象,实现了线程安全。
ThreadLocal的set方法:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
其中
ThreadLocalMap map = getMap(t);
这行代码,ThreadLocal的getMap:
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
而InheritableThreadLocal的getMap:
/** * Get the map associated with a ThreadLocal. * * @param t the current thread */ ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; }
即InheritableThreadLocal重写了和ThreadLocalMap相关的方法,其实就是把set的内容放在线程对象的inheritableThreadLocals属性上, 而普通的ThreadLocal则是把set的内容放在线程对象的threadLocals属性上。我们平时新建一个线程,new Thread(),在Thread类实例化的时候调用init()方法:
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) { if (name == null) { throw new NullPointerException("name cannot be null"); } Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); if (g == null) { /* Determine if it's an applet or not */ /* If there is a security manager, ask the security manager what to do. */ if (security != null) { g = security.getThreadGroup(); } /* If the security doesn't have a strong opinion of the matter use the parent thread group. */ if (g == null) { g = parent.getThreadGroup(); } } /* checkAccess regardless of whether or not threadgroup is explicitly passed in. */ g.checkAccess(); /* * Do we have the required permissions? */ if (security != null) { if (isCCLOverridden(getClass())) { security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } } g.addUnstarted(); this.group = g; this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); this.name = name.toCharArray(); if (security == null || isCCLOverridden(parent.getClass())) this.contextClassLoader = parent.getContextClassLoader(); else this.contextClassLoader = parent.contextClassLoader; this.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext(); this.target = target; setPriority(priority); if (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize; /* Set thread ID */ tid = nextThreadID(); }
其中
if (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
这行代码把当前线程对象的inheritableThreadLocals属性传递给新建的线程对象inheritableThreadLocals属性,即实现了线程变量的传递。
上面是可继承的线程变量inheritableThreadLocals的实现原理。但是在实际的应用场景里,绝大多数都是使用线程池来进行多线程编程,所以jdk提供的inheritableThreadLocals类实用性不高。在线程池(ThreadPoolExecutor)中运行一个Runable实例并不会去新建一个线程,而是把Runable实例添加到队列中(在核心线程数已实例化满的时候),让ThreadPoolExecutor的workers去从队列里拿出Runable实例(这是一个典型的生产者消费者模式),然后运行Runable实例.run()方法。故jdk的inheritableThreadLocals这种实现方式没法适用。
所以我就想着写一个能在executor上传递的可继承线程变量。而要实现这个功能,单单线程变量本身是不够的,还需要线程池的配合。通过我以前写的博客 http://xiangshouxiyang.iteye.com/blog/2354074 《线程池增强实现》给的思路,设计了自定义的InheritableThreadLocal:
package com.hcd; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; /** * 可在特定线程池中继承的线程变量(配合InheritableThreadLocalExecutor使用) * Created by cd_huang on 2017/8/28. */ public class InheritableThreadLocal<T> extends ThreadLocal<T>{ private static List<InheritableThreadLocal> inheritableExecutorThreadLocalList =new CopyOnWriteArrayList<>(); public InheritableThreadLocal(){ this(true); } public InheritableThreadLocal(boolean isAdd){ /** * 一般线程变量本身也不需要被垃圾回收 */ if(isAdd){ inheritableExecutorThreadLocalList.add(this); } } /** * 从map里取出内容set线程变量(protected方法,可重写,但不提倡直接调用) * @param map */ protected void setThreadLocalFromMap(Map map){ T obj = (T)map.get(this); this.set(obj); } /** * get线程变量装到map里(protected方法,可重写,但不提倡直接调用) * @param map */ protected void getThreadLocalputMap(Map map){ T obj = this.get(); map.put(this,obj); } /** * 移除掉线程变量(protected方法,可重写,但不提倡直接调用) */ protected void removeThreadLocal(){ this.remove(); } /** * 把当前线程可传递的线程变量内容放在map里,在task放进线程池队列前调用 * @return */ public static Map<Object,Object> getThreadLocalsMap(){ Map<Object,Object> threadLocalMap =new HashMap<>(); List<InheritableThreadLocal> list =inheritableExecutorThreadLocalList; for(InheritableThreadLocal threadLocal:list){ threadLocal.getThreadLocalputMap(threadLocalMap); } return threadLocalMap; } /** * 把map里的内容重新set线程变量内容,在task真正运行run方法前调用 * @param threadLocalMap */ public static void setThreadLocalsFromMap(Map<Object,Object> threadLocalMap){ List<InheritableThreadLocal> list =inheritableExecutorThreadLocalList; for(InheritableThreadLocal threadLocal:list){ threadLocal.setThreadLocalFromMap(threadLocalMap); } } /** * 把setThreadLocalsFromMap方法set的线程变量内容清空,在task真正运行run方法后调用 */ public static void removeThreadLocals(){ List<InheritableThreadLocal> list =inheritableExecutorThreadLocalList; for(InheritableThreadLocal threadLocal:list){ threadLocal.removeThreadLocal(); } } }
与之配合的InheritableThreadLocalExecutor:
package com.hcd; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; import java.util.concurrent.*; /** * 支持可继承的线程变量的线程池(配合InheritableThreadLocal使用) * Created by cd_huang on 2017/8/29. */ public class InheritableThreadLocalExecutor extends ThreadPoolExecutor { private static Logger logger = LoggerFactory.getLogger(InheritableThreadLocalExecutor.class); public InheritableThreadLocalExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } public InheritableThreadLocalExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); } public InheritableThreadLocalExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); } public InheritableThreadLocalExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); } /** * 重写执行线程实例的方法 * @param command */ @Override public void execute(Runnable command) { if (command == null){ throw new NullPointerException(); } TaskWithThreadLocal task =new TaskWithThreadLocal(command,InheritableThreadLocal.getThreadLocalsMap()); super.execute(task); } /** * 新线程执行时带上指定的线程信息 * @param */ private static class TaskWithThreadLocal implements Runnable{ private Map<Object,Object> threadLocalMap; private Runnable delegate; public TaskWithThreadLocal(Runnable delegate, Map<Object,Object> threadLocalMap){ this.delegate =delegate; this.threadLocalMap =threadLocalMap; } /** * 重写run方法,在执行run方法前设置线程变量,执行run方法后清除线程变量 * 同时,打印了运行时的异常信息,并吞掉了delegate.run()运行时的异常,不往外抛 * (线程池默认会在任务运行异常后抛出异常,并销毁掉线程对象本身,也就是如果每个任务都运行异常了,那么用线程池的效率还不如直接新建线程,详情见ThreadPoolExecutor类1123行runWorkers方法 ) * jdk线程池这样处理的意义应该是希望通过将异常抛出,将异常交给线程对象本身自带的异常处理拦截器或JVM默认的全局异常处理拦截器捕获并处理, * 这里直接去调用拦截器处理,不往外抛异常,避免线程实例的销毁 */ @Override public void run() { InheritableThreadLocal.setThreadLocalsFromMap(threadLocalMap); try{ try{ delegate.run(); //由于callable的call()方法执行过程的异常会被它的调用上级FutureTask的run()方法中处理而使异常不往外抛,为了打印异常日志这里统一进行异常日志打印的处理 if(delegate instanceof FutureTask){ try{ ((FutureTask)delegate).get(); }catch (Throwable e){ logger.error(e.getMessage(),e); Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(),e); } } }catch (Throwable e){ logger.error(e.getMessage(),e); Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(),e); } }finally { InheritableThreadLocal.removeThreadLocals(); } } } }
在Runable实例放进线程池的时候,new 一个TaskWithThreadLocal类,把线程变量放到threadLocalMap里面。实际放到线程池队列里的是TaskWithThreadLocal,TaskWithThreadLocal类的run方法执行时,会执行真正想执行的Runable实例的run方法。用TaskWithThreadLocal类传递threadLocalMap内容,有点类似jdk的InheritableThreadLocal类在Thread实例化时传递ThreadLocal.ThreadLocalMap inheritableThreadLocals。
举个例子,比如我们用线程变量记录userId。UserIdUtil:
public class UserIdUtil { private static final InheritableThreadLocal<String> userIdLocal = new InheritableThreadLocal<>(); public static String getUserId(){ return userIdLocal.get(); } public static void setUserId(String userId){ userIdLocal.set(userId); } public static void removeUserId(){ userIdLocal.remove(); } }
只需要把原本的ThreadLocal类改成InheritableThreadLocal类,即可在InheritableThreadLocalExecutor线程池中传递线程变量。
相关推荐
在C#编程中,线程池(ThreadPool)是一种管理线程资源的有效机制,它能够高效地复用线程,减少创建和销毁线程的开销。线程池中的线程通常用于执行异步任务,因此在某些场景下,我们需要判断线程池中所有的线程是否...
- **扩展性**:设计线程池时要考虑其可扩展性,以便在未来添加更多功能,如任务优先级队列、线程池的大小限制策略等。 总结来说,线程池是多线程编程中的一个重要概念,通过合理的设计和实现,可以提高程序的并发...
4. 可扩展性:考虑线程池是否方便添加新功能或与其他组件集成。 5. 社区支持:是否有活跃的社区和开发者提供持续的更新和支持。 通过`content.txt`文件,我们可以深入研究这两个线程池实现的源码,理解它们的工作...
在C#编程中,线程池(ThreadPool)是一种高效的线程管理机制,它允许开发者创建并管理多个线程,而无需直接操作线程对象。线程池中的线程可以复用,减少了创建和销毁线程的开销。当我们需要执行大量短生命周期的任务...
非阻塞线程池则采用不同的策略,它允许线程在没有任务可做时,不被阻塞,而是进入就绪状态,随时准备执行新任务。 非阻塞线程池通常基于事件驱动模型(如Java的NIO或异步I/O模型),它依赖于回调函数或者Future对象...
线程同步是为了防止数据竞争和死锁,常见的同步机制包括互斥量、信号量、同步原语(如synchronized关键字)、条件变量等。此外,线程间的通信可以通过共享内存、管道、消息队列等方式实现。 2. **线程池模型**: ...
线程池管理和多线程上传是并发编程中的一个重要实践,特别是在大数据传输和网络服务中。在Java等编程语言中,线程池通过有效地管理和复用线程资源,避免了频繁创建和销毁线程带来的开销,提升了系统性能。下面将详细...
基于线程池的Java多线程应用技术 概述: Java多线程机制是Java编程语言中的一种重要机制,它通过多线程技术提高了任务的执行效率。线程池技术是Java多线程机制中的一个重要组成部分,它能够有效地满足同类的、独立...
线程池是一种多线程处理形式,它预先创建了若干数量的可执行线程并放在一个池子中,需要的时候直接拿来使用,使用完毕后再放回池中。线程池技术的优势在于:能够减少在创建和销毁线程上的开销;能够有效控制最大并发...
在C#编程中,线程和线程池是并发编程中的关键概念,特别是在开发Windows桌面应用程序(Winform)时,为了提升程序的响应性和效率,理解并熟练运用这些技术至关重要。本文将深入探讨如何在Winform应用中使用异步多...
在提供的`threadpool.c`文件中,我们可以看到具体的C语言实现细节,包括如何初始化线程池、提交任务、销毁线程池以及线程回调函数的定义等。`简单Linux C线程池 - venow - 博客园.mht`文件可能包含了一篇关于如何在...
Java线程池是一种高效管理线程资源的工具,它能够帮助开发者有效地控制并发执行的线程数量,提高系统性能,并确保程序的稳定性和可维护性。在Java中,线程池的实现主要依赖于`java.util.concurrent`包中的`...
在C#编程中,线程和线程池是并发处理的核心概念,特别是在处理大量异步任务或需要同时执行多个操作的场景下。本资源“xianchengchi.rar”提供了关于C#线程池的演示程序,帮助开发者深入理解并应用线程池技术。 线程...
总之,线程池和多线程是现代软件开发中不可或缺的技术,它们能帮助我们构建高效、响应迅速的应用。在VC环境下,理解并熟练掌握这些概念和实现方式,对于提升程序性能和编写高质量代码至关重要。通过分析和学习WQDemo...
线程池是多线程编程中的一个重要概念,它在现代软件开发中被广泛使用,特别是在高性能服务器和并发处理大量任务的场景中。本资源“VC_Thread_Pools.rar”提供了在VC++ 6.0环境下实现线程池的一个实例,帮助开发者...
C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池...
标题中的“免积分C++11写的可复用的线程池类 - 开源”意味着这是一个使用C++11标准库实现的线程池类,它具有可复用性,并且是开源的,允许开发者查看和修改源代码,以便根据项目需求进行定制。 线程池是一种多线程...
1. **创建线程任务**:定义一个继承自`QRunnable`的类,用于执行下载任务。这个类应包含下载URL、目标保存路径等信息,以及执行下载的具体逻辑,比如使用`QNetworkAccessManager`发起HTTP请求并接收数据。 2. **...
在这个"多线程互斥实例 多线程获取同一变量"的示例中,我们将探讨如何在多个线程中安全地访问共享资源,避免数据不一致性和竞态条件。 首先,我们需要理解多线程中的一些核心概念: 1. **线程**:线程是操作系统...
3. `newCachedThreadPool()`: 创建一个可缓存的线程池,当线程空闲超过60秒,线程会自动终止,适合处理大量短生命周期的任务。 4. `newScheduledThreadPool(int corePoolSize)`: 创建一个定长的线程池,支持定时及...