delphi 线程池基础 TSimplePool

1. TSimpleThread

2. TSimpleList

3. 以1,2构成 TSimplePool

用法

先定义: TDoSomeThingThread=class(TSimpleThread) ;

并给 TDoSomeThingThread reintroduce Create 不带参数的构造函数。

再定义  TDoSomeThingPool=class(TSimpleTool<TDoSomeThing>);

最后,只需在 TDoSomeThingPool 写线程调度的代码就行了,可以省不少事。(这部分有待进一步完善)

全部源码下载

  1 unit uSimpleThread;
  2 interface
  3 uses
  4   System.Classes, System.SysUtils, System.SyncObjs;
  5
  6 type
  7
  8   // 显示信息,调用方法 DoOnStatusMsg(AMsg);
  9   TOnStatusMsg = procedure(AMsg: string) of object;
 10
 11   // 显示调试信息,一般用于显示出错信息,用法 DoOnDebugMsg(AMsg);
 12   TOnDebugMsg = TOnStatusMsg;
 13
 14   TSimpleThread = class(TThread)
 15   public type // "执行过程"的类别定义
 16
 17     TGeneralProc = procedure; // 普通的,即 procedure DoSomeThing;
 18     TObjectProc = procedure of object; // 类的,即 TXxxx.DoSomeThign; 用得多
 19     TAnonymousProc = reference to procedure; // 匿名的
 20   private type
 21     TProcKind = (pkGeneral, pkObject, pkAnonymous); // "执行过程"的类别
 22   private
 23
 24     FGeneralProc: TGeneralProc;
 25     FObjProc: TObjectProc;
 26     FAnoProc: TAnonymousProc;
 27
 28     FProcKind: TProcKind;
 29
 30     FEvent: TEvent; // 用于阻塞,它是一个信号量
 31     FActiveX: boolean; // 是否在线程中支持 Com ,如果你要在线程中访问 IE 的话,就设定为 True
 32
 33     FOnStatusMsg: TOnStatusMsg;
 34     FOnDebugMsg: TOnDebugMsg;
 35
 36     FTagID: integer; // 给线程一个代号,在线程池的时候用来作区别
 37     FParam: integer; // 给线程一个参数,方便识别
 38
 39     procedure SelfStart; // 触发线程运行
 40
 41     procedure DoExecute; // 这个函数里面运行的代码是“线程空间”
 42     procedure DoOnException(e: exception); // 异常信息显示 调用 DoOnDebugMsg(AMsg);
 43
 44     procedure SetTagID(const Value: integer);
 45     procedure SetParam(const Value: integer);
 46
 47     procedure SetOnStatusMsg(const Value: TOnStatusMsg);
 48     procedure SetOnDebugMsg(const Value: TOnDebugMsg);
 49
 50   protected
 51
 52     FWaitStop: boolean; // 结束标志,可以在继承类中使用它,以确定线程是否停止运行
 53
 54     procedure DoOnStatusMsg(AMsg: string); // 显示普通信息
 55     procedure DoOnDebugMsg(AMsg: string); // 显示调式信息
 56
 57     procedure Execute; override; // 重载 TThread.Execute
 58
 59     procedure OnThreadProcErr(e: exception); virtual; // 异常发生事件
 60
 61     procedure WaitThreadStop; // 等待线程结束
 62
 63     procedure BeforeExecute; virtual; // 看名字,不解释
 64     Procedure AfterExecute; virtual; // 看名字,不解释
 65
 66     procedure SleepExceptStopped(ATimeOut: Cardinal); // 这个高大上了,要解释一下。
 67     { 有时线程没有任务时,就会休息一会儿,但是,休息的时候,可能会接收到退出线程的指令
 68       此函数就是在休息的时候也检查一下停止指令
 69     }
 70
 71   public
 72
 73     // 改变一下 Create 的参数,AllowedActiveX:是否允许线程代码访问 Com
 74     constructor Create(AllowedActiveX: boolean = false); reintroduce;
 75
 76     destructor Destroy; override;
 77
 78     procedure ExeProcInThread(AProc: TGeneralProc); overload; // 这三个,对外的接口。
 79     procedure ExeProcInThread(AProc: TObjectProc); overload;
 80     procedure ExeProcInThread(AProc: TAnonymousProc); overload;
 81
 82     procedure StartThread; virtual;
 83     { 启动线程,一般只调用一次。
 84       以后就由线程的响应事件来执行了
 85     }
 86
 87     procedure StopThread; virtual; // 停止线程
 88
 89     property OnStatusMsg: TOnStatusMsg read FOnStatusMsg write SetOnStatusMsg;
 90     property OnDebugMsg: TOnDebugMsg read FOnDebugMsg write SetOnDebugMsg;
 91     property WaitStop: boolean read FWaitStop;
 92     property TagID: integer read FTagID write SetTagID;
 93     property Param: integer read FParam write SetParam;
 94
 95   end;
 96
 97 implementation
 98
 99 uses
100   ActiveX;
101
102 procedure TSimpleThread.AfterExecute;
103 begin
104 end;
105
106 procedure TSimpleThread.BeforeExecute;
107 begin
108 end;
109
110 constructor TSimpleThread.Create(AllowedActiveX: boolean);
111 var
112   BGUID: TGUID;
113 begin
114   inherited Create(false);
115   FActiveX := AllowedActiveX;
116   FreeOnTerminate := false; // 我们要手动Free线程
117   CreateGUID(BGUID);
118   FEvent := TEvent.Create(nil, true, false, GUIDToString(BGUID));
119 end;
120
121 destructor TSimpleThread.Destroy;
122 begin
123   StopThread; // 先停止
124   WaitThreadStop; // 再等待线程停止
125   {
126     在继承类的 Destroy 中,也要写上这两句. 如:
127     暂时未找到更好的办法,这点代码省不了
128     destructor TXXThread.Destroy;
129     begin
130     StopThread;
131     WaitThreadStop;
132     xxx.Free;
133     Inherited;
134     end;
135   }
136   FEvent.Free;
137   inherited;
138 end;
139
140 procedure TSimpleThread.DoExecute; // 此函数内执行的代码,就是在多线程空间里运行
141 begin
142   BeforeExecute;
143   repeat
144
145     FEvent.WaitFor;
146     FEvent.ResetEvent; // 下次waitfor 一直等
147     { 这里尝试了很多些,总 SelfStart 觉得有冲突,经过多次修改并使用证明,
148       没有必要在这里加锁,因为只调用 startThread 一次,剩下的交给线程影应事件
149     }
150
151     if not Terminated then // 如果线程需要退出
152     begin
153
154       try
155
156         case FProcKind of
157           pkGeneral: FGeneralProc;
158           pkObject: FObjProc;
159           pkAnonymous: FAnoProc;
160         end;
161
162       except
163
164         on e: exception do
165         begin
166           DoOnException(e);
167         end;
168
169       end;
170
171     end;
172
173   until Terminated;
174   AfterExecute;
175   //代码运行到这里,就表示这个线程不存在了。再也回不去了,必须释放资源了。
176 end;
177
178 procedure TSimpleThread.DoOnDebugMsg(AMsg: string);
179 begin
180   if Assigned(FOnDebugMsg) then
181     FOnDebugMsg(AMsg);
182 end;
183
184 procedure TSimpleThread.DoOnException(e: exception);
185 var
186   sErrMsg: string;
187 begin
188   sErrMsg := ‘ClassName:‘ + ClassName + #13#10;
189   sErrMsg := sErrMsg + ‘TagID:‘ + IntToStr(FTagID) + #13#10;
190   sErrMsg := sErrMsg + ‘Param:‘ + IntToStr(Param) + #13#10;
191   sErrMsg := sErrMsg + ‘ErrMsg:‘ + e.Message + #13#10;
192   DoOnDebugMsg(sErrMsg);
193   OnThreadProcErr(e);
194 end;
195
196 procedure TSimpleThread.DoOnStatusMsg(AMsg: string);
197 begin
198   if Assigned(FOnStatusMsg) then
199     FOnStatusMsg(AMsg);
200 end;
201
202 procedure TSimpleThread.Execute;
203 begin
204   //是否支持 Com
205   if FActiveX then
206   begin
207     CoInitialize(nil);
208     try
209       DoExecute;
210     finally
211       CoUninitialize;
212     end;
213   end
214   else
215     DoExecute;
216 end;
217
218 procedure TSimpleThread.ExeProcInThread(AProc: TGeneralProc);
219 begin
220   FGeneralProc := AProc;
221   FProcKind := pkGeneral;
222   SelfStart;
223 end;
224
225 procedure TSimpleThread.ExeProcInThread(AProc: TObjectProc);
226 begin
227   FObjProc := AProc;
228   FProcKind := pkObject;
229   SelfStart;
230 end;
231
232 procedure TSimpleThread.ExeProcInThread(AProc: TAnonymousProc);
233 begin
234   FAnoProc := AProc;
235   FProcKind := pkAnonymous;
236   SelfStart;
237 end;
238
239 procedure TSimpleThread.OnThreadProcErr(e: exception);
240 begin;
241 end;
242
243 procedure TSimpleThread.SelfStart;
244 begin
245   //经常多次尝试,最终写成这样,运行没有问题
246   if FEvent.WaitFor(0) <> wrSignaled then
247     FEvent.SetEvent; // 让waitfor 不再等
248 end;
249
250 procedure TSimpleThread.StopThread;
251 begin
252   //继承类的代码中,需要检查 FWaitStop ,来控制线程结束
253   FWaitStop := true;
254 end;
255
256 procedure TSimpleThread.SetOnDebugMsg(const Value: TOnDebugMsg);
257 begin
258   FOnDebugMsg := Value;
259 end;
260
261 procedure TSimpleThread.SetOnStatusMsg(const Value: TOnStatusMsg);
262 begin
263   FOnStatusMsg := Value;
264 end;
265
266 procedure TSimpleThread.SetParam(const Value: integer);
267 begin
268   FParam := Value;
269 end;
270
271 procedure TSimpleThread.SetTagID(const Value: integer);
272 begin
273   FTagID := Value;
274 end;
275
276 procedure TSimpleThread.SleepExceptStopped(ATimeOut: Cardinal);
277 var
278   BOldTime: Cardinal;
279 begin
280   // sleep 时检测退出指令,以确保线程顺序退出
281   // 多个线程同时工作,要保证正确退出,确实不容易
282   BOldTime := GetTickCount;
283   while not WaitStop do
284   begin
285     sleep(50);
286     if (GetTickCount - BOldTime) > ATimeOut then
287       break;
288   end;
289 end;
290
291 procedure TSimpleThread.StartThread;
292 begin
293   FWaitStop := false;
294 end;
295
296 procedure TSimpleThread.WaitThreadStop;
297 begin
298   //等待线程结束
299   StopThread;
300   Terminate;
301   SelfStart;
302   WaitFor;
303 end;
304
305 end.

uSimpleThread.pas

  1 unit uSimpleList;
  2
  3 interface
  4
  5 uses
  6   Generics.Collections;
  7
  8 type
  9
 10   TSimpleList<T> = class(TList<T>)
 11   private
 12     FCurIndexPos: integer;
 13     function DoPopByIndex(Index: integer): T;
 14     procedure FreeAllItems;
 15     procedure SetCurIndexPos(const Value: integer);
 16   protected
 17     FNeedFreeItem: boolean;
 18     procedure FreeItem(Item: T); virtual; //子类可以重截这个以确定该如何释放
 19   public
 20
 21     constructor Create;
 22     destructor Destroy; override;
 23
 24     procedure Lock; //新版的Lock功能值得学习
 25     procedure Unlock; //
 26
 27     function PopFirst: T; //不解释,下同
 28     function PopLast: T;
 29     function PopByIndex(Index: integer): T;
 30
 31     procedure ClearAndFreeAllItems; //清空并释放所有的Item
 32     property CurIndexPos: integer read FCurIndexPos write SetCurIndexPos;
 33
 34   end;
 35
 36   //加 Constructor 限制是要求 T 要有一个没带参数的Create函数,也就是构造器
 37   TClassSimpleList<T: Class, Constructor> = class(TSimpleList<T>)
 38   protected
 39     procedure FreeItem(Item: T); override;
 40     function AddNewOne: T;// T有了Create 才能写这个
 41   end;
 42
 43 implementation
 44
 45 procedure TSimpleList<T>.ClearAndFreeAllItems;
 46 begin
 47   FreeAllItems;
 48   clear;
 49 end;
 50
 51 constructor TSimpleList<T>.Create;
 52 begin
 53   inherited;
 54   FNeedFreeItem := true;
 55   FCurIndexPos := -1;
 56 end;
 57
 58 destructor TSimpleList<T>.Destroy;
 59 begin
 60   FreeAllItems;
 61   inherited;
 62 end;
 63
 64 function TSimpleList<T>.DoPopByIndex(Index: integer): T;
 65 begin
 66   if (index >= 0) and (index <= count - 1) then
 67   begin
 68     result := items[index];
 69     Delete(index);
 70     Exit;
 71   end;
 72   result := T(nil);
 73 end;
 74
 75 procedure TSimpleList<T>.FreeAllItems;
 76 var
 77   Item: T;
 78 begin
 79   if FNeedFreeItem then
 80   begin
 81     FCurIndexPos := -1;
 82     for Item in self do
 83       FreeItem(Item);
 84   end;
 85 end;
 86
 87 procedure TSimpleList<T>.FreeItem(Item: T);
 88 begin
 89   // 假设 T 是 PMyRec =^TMyRec  TMyRec=record;
 90   // 这个写法对吗?
 91   // if GetTypeKind(T) = tkPointer then
 92   // begin
 93   // Dispose(Pointer(Pointer(@Item)^));
 94   // end;
 95   // 此写法未认真测试所以不使用。
 96   // 如果 Item 是指针,我在继承类中的 FreeItem 中写 Dispose(Item);
 97 end;
 98
 99 procedure TSimpleList<T>.Lock;
100 begin
101   system.TMonitor.Enter(self);
102 end;
103
104 procedure TSimpleList<T>.Unlock;
105 begin
106   system.TMonitor.Exit(self);
107 end;
108
109 function TSimpleList<T>.PopByIndex(Index: integer): T;
110 begin
111   result := DoPopByIndex(index);
112 end;
113
114 function TSimpleList<T>.PopFirst: T;
115 begin
116   result := DoPopByIndex(0);
117 end;
118
119 function TSimpleList<T>.PopLast: T;
120 begin
121   result := DoPopByIndex(count - 1);
122 end;
123
124 procedure TSimpleList<T>.SetCurIndexPos(const Value: integer);
125 begin
126   FCurIndexPos := Value;
127 end;
128
129 { TThreadClassList<T> }
130
131 function TClassSimpleList<T>.AddNewOne: T;
132 begin
133   result := T.Create();
134   Add(result);
135 end;
136
137 procedure TClassSimpleList<T>.FreeItem(Item: T);
138 begin
139   Item.Free;
140 end;
141
142 end.

uSimpleList.pas

  1 unit uSimplePool;
  2
  3 interface
  4
  5 uses
  6   uSimpleThread, uSimpleList, uSyncObjs, System.Generics.Collections;
  7
  8 Type
  9
 10   TSimplePool<T: TSimpleThread, Constructor> = class
 11   private Type
 12     TWorkThreadList = Class(TClassSimpleList<T>);
 13   private
 14
 15     FOnStatusMsg: TOnStatusMsg;
 16     FOnDebugMsg: TOnDebugMsg;
 17     FMaxThreadCount: integer;
 18
 19     procedure SetOnDebugMsg(const Value: TOnDebugMsg);
 20     procedure SetOnStatusMsg(const Value: TOnStatusMsg);
 21     procedure SetMaxThreadCount(const Value: integer);
 22     procedure InitThreadList(AThreadCount: integer);
 23
 24   protected
 25
 26     FStopThreadCount: integer;
 27     FWorkThreadList: TWorkThreadList;
 28     FEvent: TSuperEvent; //提供给继承类阻塞用
 29
 30     procedure DoOnStatusMsg(AMsg: string);
 31     procedure DoOnDebugMsg(AMsg: string);
 32     procedure OnEachNewWorkThread(AWorkThread: T); virtual;
 33
 34   public
 35
 36     property OnStatusMsg: TOnStatusMsg read FOnStatusMsg write SetOnStatusMsg;
 37     property OnDebugMsg: TOnDebugMsg read FOnDebugMsg write SetOnDebugMsg;
 38
 39     constructor Create;
 40     destructor Destroy; override;
 41
 42     procedure StartWork; virtual;
 43     procedure StopWork; virtual;
 44
 45     property MaxThreadCount: integer read FMaxThreadCount write SetMaxThreadCount default 5;
 46
 47   end;
 48
 49 const
 50   cnDefaultWorkThreadCount = 5;
 51   cnLimitedWorkTreadCount = 20;
 52
 53 implementation
 54
 55 { TSimplePool }
 56
 57 procedure TSimplePool<T>.DoOnDebugMsg(AMsg: string);
 58 begin
 59   if Assigned(FOnDebugMsg) then
 60     FOnDebugMsg(AMsg);
 61 end;
 62
 63 procedure TSimplePool<T>.DoOnStatusMsg(AMsg: string);
 64 begin
 65   if Assigned(FOnStatusMsg) then
 66     FOnStatusMsg(AMsg);
 67 end;
 68
 69 procedure TSimplePool<T>.InitThreadList(AThreadCount: integer);
 70 var
 71   i, nTagID: integer;
 72   B: T;
 73 begin
 74   nTagID := FWorkThreadList.Count;
 75   for i := 0 to AThreadCount do
 76   begin
 77     B := FWorkThreadList.AddNewOne;
 78     B.TagID := nTagID;
 79     B.OnStatusMsg := self.DoOnStatusMsg;
 80     B.OnDebugMsg := self.DoOnDebugMsg;
 81     OnEachNewWorkThread(B);
 82     inc(nTagID);
 83   end;
 84 end;
 85
 86 procedure TSimplePool<T>.OnEachNewWorkThread(AWorkThread: T);
 87 begin
 88 end;
 89
 90 procedure TSimplePool<T>.SetMaxThreadCount(const Value: integer);
 91 var
 92   ndiff: integer;
 93 begin
 94   FMaxThreadCount := Value;
 95   if FMaxThreadCount > cnLimitedWorkTreadCount then
 96     FMaxThreadCount := cnLimitedWorkTreadCount;
 97   if FMaxThreadCount <= 0 then
 98     FMaxThreadCount := 1;
 99   ndiff := FMaxThreadCount - FWorkThreadList.Count;
100   InitThreadList(ndiff);
101 end;
102
103 procedure TSimplePool<T>.SetOnDebugMsg(const Value: TOnDebugMsg);
104 begin
105   FOnDebugMsg := Value;
106 end;
107
108 procedure TSimplePool<T>.SetOnStatusMsg(const Value: TOnStatusMsg);
109 begin
110   FOnStatusMsg := Value;
111 end;
112
113 procedure TSimplePool<T>.StartWork;
114 var
115   i: integer;
116 begin
117   for i := 1 to MaxThreadCount do
118   begin
119     FWorkThreadList[i].StartThread;
120   end;
121 end;
122
123 procedure TSimplePool<T>.StopWork;
124 var
125   B: T;
126 begin
127   for B in FWorkThreadList do
128   begin
129     B.StopThread;
130   end;
131 end;
132
133 constructor TSimplePool<T>.Create;
134 begin
135   inherited Create;
136   FMaxThreadCount := 5;
137   FEvent := TSuperEvent.Create;
138   FWorkThreadList := TWorkThreadList.Create;
139   InitThreadList(cnDefaultWorkThreadCount);
140 end;
141
142 destructor TSimplePool<T>.Destroy;
143 begin
144   FWorkThreadList.Free;
145   FEvent.Free;
146   inherited Destroy;
147 end;
148
149 end.

uSimplePool.pas

 1 unit uSyncObjs;
 2
 3 interface
 4
 5 uses
 6   SyncObjs;
 7
 8 Type
 9
10   TSuperEvent = class(TEvent)
11   public
12     constructor Create; reintroduce;
13   end;
14
15 implementation
16
17 { TSuperEvent }
18 uses
19   SysUtils;
20
21 constructor TSuperEvent.Create;
22 var
23   BGUID: TGUID;
24 begin
25   CreateGUID(BGUID);
26   inherited Create(nil, true, false, GUIDToString(BGUID));
27 end;
28
29 end.

uSyncObjs.pas

时间: 2024-08-02 10:55:25

delphi 线程池基础 TSimplePool的相关文章

Java(Android)线程池---基础篇

1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? 1 newThread(newRunnable(){ 2 3 @Override 4 publicvoidrun(){ 5 // TODO Auto-generated method stub 6 } 7 }).start(); 那你就out太多了,new Thread的弊端如下: a. 每次new Thread新建对象性能差.b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致

Java:线程池基础

基本认识 以下摘自百度百科 线程池的概念:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务. 线程池的作用:在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资

c# 多线程线程池基础

线程池的作用        在上一篇中我们了解了创建和销毁线程是一个昂贵的操作,要耗费大量的时间,太多的线程会浪费内存资源,当线程数量操作计算机CPU的数量后操作系统必须调度可运行的线程并执行上下文切换,所有太多的线程还会影响性能,那么有没有办法让线程可以重复使用了,让线程干完活之后不用销毁,把它放在一个容器中, 等待下次有任务的时候在从容器中取出来就行了,这样就避免了创建和销毁所带来的性能损耗,所有线程池的作用总结起来就是:因为创建一个线程的代价较高,因此我们使用线程池设法复用线程. 线程基础

Delphi线程池

unit uThreadPool; {   aPool.AddRequest(TMyRequest.Create(RequestParam1, RequestParam2, ...)); } interfaceuses  Windows,  Classes; // 是否记录日志// {$DEFINE NOLOGS} type  TCriticalSection = class(TObject)  protected    FSection: TRTLCriticalSection;  publi

并发编程—7.2线程池基础

目录 1.什么是线程池?为什么要用线程池? 2.实现一个我们自己的线程池 3.JDK中的线程池和工作机制 3.1 线程池的创建 3.2 提交任务 3.3 关闭线程池 3.4 工作机制 4.合理配置线程池 5.预定义的线程池 6.Executor框架 7.了解CompletionService 1.什么是线程池?为什么要用线程池? 降低资源的消耗.线程的创建和销毁 提高响应速度.线程的创建时间为T1,执行时间T2,销毁时间T3,免去T1和T3的时间 提高线程的可管理性. 2.实现一个我们自己的线程

线程池基础篇

一.什么是线程池?为什么要用线程池? 1. 降低资源的消耗.降低线程创建和销毁的资源消耗: 2. 提高响应速度:线程的创建时间为T1,执行时间T2,销毁时间T3,免去T1和T3的时间 3. 提高线程的可管理性. 二.线程池的创建 ThreadPoolExecutor,jdk所有线程池实现的父类 三.参数介绍 先看构造函数: /** * Creates a new {@code ThreadPoolExecutor} with the given initial * parameters. * *

线程池基础

package com.how2java.tmall.train.ThreadPool; import java.util.concurrent.*; import static java.util.concurrent.TimeUnit.NANOSECONDS; /** * @Author: yslu * @Date: 2019-09-30 8:44 * @description: */ public class ThreadPoolExecutorDemo { public static v

Java线程池-基础

线程池的核心类:ThreadPoolExecutor ,类图如下: (I:代表接口,C:代表实现类) I:Executor I:ExecutorService C:AbstractExecutorService C:ThreadPoolExecutor 构造函数: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Run

Delphi ThreadPool 线程池(Delphi2009以上版本适用)

http://blog.sina.com.cn/s/blog_6250a9df0101kref.html 在网上查找Delphi线程池,结果发现寥寥无几. 看了半天源代码,弄得一头雾水,觉得不容易理解和使用,于是自己想写一个线程池. 什么样的线程池更好呢? 我觉得使用起来要可靠,并且一定要简单,这样才是更好的. 我写的线程池就是这样一个标准,使用非常简单,只传入自己要执行的方法就可以了, 其实大家最后就是关注自己要操作的方法,其余的交给线程池.全部源代码如下: { {单元:ThreadPoolU