volatile关键字是什么样起效果的?

流程图:

——————————————————————————————————————————————————————————————————————

 

public class VolatileTest {
    public static volatile int race = 0;

    public static void increase(){
        race++;
    }

    private static final int THREAD_COUNT = 20;

    public static void main(String[] args) {
        Thread[] threads = new Thread[THREAD_COUNT];
        for(int i = 0; i < THREAD_COUNT; i++){
            threads[i] = new Thread(new Runnable() {

                @Override
                public void run() {
                    for(int i = 0; i < 1000; i++){
                        increase();
                    }
                }
            });
            threads[i].start();
        }
        while(Thread.activeCount() > 1){
            Thread.yield();
        }
        System.out.println(race);
    }
}

贰)        
撤销执行上下文流动除了使用ExecutionContext.SuppressFlow()格局外。还足以透过动用ThreadPool的UnsafeQueueUserWorkItem

UnsafeRegisterWaitForSingleObject来举行委托方法。原因是不安全的线程池操作不会传导压缩堆栈。每当压缩堆栈流动时,托管的本位、同步、区域设置和用户上下文也随之流动。

由此JIT编译之后就会多执行一个“lock”操作,那个操作相当于贰个内部存储器屏障,指重排序之后,不能够讲屏障之后的操作放到屏障在此之前。

 

导致不安全的原委实在依旧Java运算是非原子操作。所谓原子操作是指操作的实施不会被线程的调度给卡住

  1. 亟需前台线程。(线程池线程“始终”是后台线程)
  2. 亟需使线程具有特定的先期级。(线程池线程都是暗中同意优先级,“不提议”实行改动)
  3. 职务会长期占据线程。由于线程池具有最大线程数限制,由此大批量占用线程池线程大概会阻拦职责运营。
  4. 急需将线程放入单线程单元(STA)。(所有ThreadPool线程“始终”是四线程单元(MTA)中)
  5. 急需全数与线程关联的平安标识,或使某1线程专用于某一职分。

重点字volatile是Java虚拟机提供的最轻量级的壹块机制,然则在常常的品类里面,遭逢要求多线程的时候愈来愈多地应用的是synchronized关键字来进展协同。个人而言,越多的来由是对volatile关键字的机制不领悟造成的。

 

1般说来变量的值在县城之间传递均要求经过主内部存款和储蓄器来完毕,例如,线程A修改一个常常变量的值,然后向内部存款和储蓄器实行会写,别的一条线程B在线程A回写完之后再从主内部存储器中实行读取操作,新变量值才会对线程B可知。

 摘自:http://www.cnblogs.com/heyuquan/archive/2012/12/23/threadPool-manager.html

上面那段代码就显示了三个很好的volatile的应用情形:

 

就算volatile定义的变量对全数的线程都是可知的,然则并不能够印证volatile定义的变量的演算在并发下正是平安的。

下边给出2个示范为了演示:

然而到底并不能够说volatile有怎么着执行的飞快的特色,但其开发是比锁低的,,唯1须求看的是volatile是或不是满足使用意况。

a)        
若直接接纳Thread.CurrentThread.ExecutionContext则会报“不能利用以下上下文:
跨 AppDomains 封送的上下文、不是透过捕获操作获取的上下文或已当做 Set
调用的参数的上下文。”错误。

当shutdown()方法被调用的时候,能有限支撑所用的doWork()方法都停下来。

  1. 排队办事项

Java内存模型对volatile专门定义了一些非正规的走访规则,当多个变量定义为volatile之后便具有了二种特性:

图片 1图片 2

接下去是第3个地方的用途,普通变量仅仅会保险在该方法执行进度中有着正视赋值结果的地点都能获得正确的结果,而不可能保险变量赋值的操作顺序与程序代码的施行各种一致。

《异步编制程序:线程概述及利用》中笔者关系了Thread的三个上下文,即:

图片 3

三)         静态方法GetAvailableThreads()

volatile Boolean shutdownRequset;

public void shutdown() {
    shutdownRequset = true;
}

public void doWork() {
    while(!shutdownRequest){
        ...          
    }
}

 

出于volatile变量智能有限支撑可知性,还是亟待synchronized和java.util.concurrent中的原子类来担保线程的平安。

格局Get马克斯Threads()、Set马克斯Threads()、GetMinThreads()、SetMinThreads()、GetAvailableThreads()钧包蕴三个参数。参数workerThreads指工作者线程;参数completionPortThreads指异步
I/O 线程。

public class Singleton {

    private volatile static Singleton instance;

    public static Singleton getInstance(){
        if(instance == null){
            synchronized (Singleton.class) {
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    public static void main(String[] args) {
        Singleton.getInstance();
    }
}

于今大家都早已知道线程池为大家提供了福利的异步API及托管的线程管理。那么是否任几时候都应有使用线程池线程呢?当然不是,我们依然要求“因地制宜”的,在以下两种景况下,适合于成立并管制本人的线程而不是使用线程池线程:

 

private static void Example_RegisterWaitForSingleObject()
{
    // 加endWaitHandle的原因:如果执行过快退出方法会导致一些东西被释放,造成排队的任务不能执行,原因还在研究
    AutoResetEvent endWaitHandle = new AutoResetEvent(false);

    AutoResetEvent notificWaitHandle = new AutoResetEvent(false);
    AutoResetEvent waitHandle = new AutoResetEvent(false);
    RegisteredWaitHandle registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(
        waitHandle,
        (Object state, bool timedOut) =>
        {
            if (timedOut)
                Console.WriteLine("RegisterWaitForSingleObject因超时而执行");
            else
                Console.WriteLine("RegisterWaitForSingleObject收到WaitHandle信号");
        },
        null, TimeSpan.FromSeconds(2), true
     );

    // 取消等待操作(即不再执行WaitOrTimerCallback委托)
    registeredWaitHandle.Unregister(notificWaitHandle);

    // 通知
    ThreadPool.RegisterWaitForSingleObject(
        notificWaitHandle,
        (Object state, bool timedOut) =>
        {
            if (timedOut)
                Console.WriteLine("第一个RegisterWaitForSingleObject没有调用Unregister()");
            else
                Console.WriteLine("第一个RegisterWaitForSingleObject调用了Unregister()");

            endWaitHandle.Set();
        },
        null, TimeSpan.FromSeconds(4), true
     );

    endWaitHandle.WaitOne();
}

increase()方法的履行1起是4条字节码指令达成的,熟练字节码命令的能够看到着4步的操作,

 

(在依次线程的劳作内部存款和储蓄器中,volatile变量也得以存在不1致的场馆,可是出于每一回使用从前都已经刷新了,执行引擎看不到不相同等的气象,所以便觉得不设有不平等的景色)

         示例:

 

通过调用 ThreadPool.QueueUserWorkItem 并传递 WaitCallback
委托来使用线程池。也能够经过行使 ThreadPool.RegisterWaitForSingleObject
并传递 WaitHandle(在向其发出时域信号或逾期时,它将引发对由
WaitOrTimerCallback
委托包装的章程的调用)来将与等待操作相关的工作项排队到线程池中。若要裁撤等待操作(即不再履行WaitOrTimerCallback委托),可调用RegisterWaitForSingleObject()方法再次回到的RegisteredWaitHandle的
Unregister 方法。

不畏编写翻译出来的唯有一条字节码指令,但也不意味那是3个原子操作。

        
当Windows上下文切换来另2个线程时,CPU将实施三个不等的线程,而以前线程的代码和数量还在CPU的高速缓存中,(高速缓存使CPU不必平常访问RAM,RAM的快慢比CPU高速缓存慢得多),当Windows上下文切换来几个新线程时,那个新线程极有十分大可能率要执行不一的代码并访问分歧的数码,这一个代码和数量不在CPU的高速缓存中。由此,CPU必须访问RAM来填充它的高速缓存,以恢复生机相当的慢实市价况。可是,在其“时间片”执行完后,1遍新的线程上下文切换又发出了。

造成的缘由是race++操作并不是二个原子操作,尽管看来它唯有一句话,不过在编写翻译时并不是这么的。用javap命名举行反编写翻译,同时输出附加消息:

 

如下边那段代码:

Windows实际记录了各样线程被上下文切换成的次数。能够行使像Microsoft
Spy++那样的工具查看那一个数额。那几个工具是Visual
Studio附带的3个小工具(vs按安装路径\Visual Studio
2012\Common7\Tools),如图

接下去将对上述多个方面分别介绍:

二)         ExecutionContext   
获取2个System.Threading.ExecutionContext对象,该对象涵盖关于当前线程的各个上下文的新闻。首要用来线程间数据共享。

 

public sealed class ObjectPool<T> where T : ICacheObjectProxy<T>
{
    // 最大容量
    private Int32 m_maxPoolCount = 30;
    // 最小容量
    private Int32 m_minPoolCount = 5;
    // 已存容量
    private Int32 m_currentCount;
    // 空闲+被用 对象列表
    private Hashtable m_listObjects;
    // 最大空闲时间
    private int maxIdleTime = 120;
    // 定时清理对象池对象
    private Timer timer = null;

    /// <summary>
    /// 创建对象池
    /// </summary>
    /// <param name="maxPoolCount">最小容量</param>
    /// <param name="minPoolCount">最大容量</param>
    /// <param name="create_params">待创建的实际对象的参数</param>
    public ObjectPool(Int32 maxPoolCount, Int32 minPoolCount, Object[] create_params){ }

    /// <summary>
    /// 获取一个对象实例
    /// </summary>
    /// <returns>返回内部实际对象,若返回null则线程池已满</returns>
    public T GetOne(){ }

    /// <summary>
    /// 释放该对象池
    /// </summary>
    public void Dispose(){ }

    /// <summary>
    /// 将对象池中指定的对象重置并设置为空闲状态
    /// </summary>
    public void ReturnOne(T obj){ }

    /// <summary>
    /// 手动清理对象池
    /// </summary>
    public void ManualReleaseObject(){ }

    /// <summary>
    /// 自动清理对象池(对大于 最小容量 的空闲对象进行释放)
    /// </summary>
    private void AutoReleaseObject(Object obj){ }
}

 

图片 4图片 5

 

 

2.
不准指令重排序优化。

上下文切换所发出的费用不会换到任何内部存款和储蓄器和属性上的入账。执行上下文所需的小运取决于CPU架构和进程(即“时间片”的分配)。而填充CPU缓存所需的岁月取决于系统运行的应用程序、CPU、缓存的大小以及别的种种因素。所以,不可能为每3遍线程上下文切换的时刻支出给出二个鲜明的值,甚至无法提交3个测度的值。唯壹明确的是,假使要塑造高品质的应用程序和零部件,就应当尽量幸免线程上下文切换。

一旦定义的变量没有被volatile修饰,那么就有望鉴于指令重排的优化而招致执行各样的颠倒。

在线程池运转中,对于实施完职责的线程池线程,不会立马销毁,而是重返到线程池,线程池会维护最小的空闲线程数(尽管应用程序所无线程都是悠闲状态),以便队列职务能够立即运维。超越此最小数指标空余线程一段时间没事做后会自个儿醒来终止自个儿,以节省系统能源。

21个线程,各样线程会对race变量实行一千次自增操作,即race++。输出的结果应该是30000,可是会发觉每一趟运转的结果都不一致,而且都以一个低于三千0的数。

ThreadPool

一.
保险此变量对拥有线程的可见性,“可知性”指当一条线程修改了那么些变量的值,新的值对与其它线程来说是立即意识到的。

实行上下文包含:安全上下文、同步上下文(System.Threading.SynchronizationContext)、逻辑调用上下文(System.Runtime.Messaging.CallContext)。即:安全设置(压缩栈、Thread的Principal属性和Windows身份)、宿主设置(System.Threading.HostExcecutingContextManager)以及逻辑调用上下文数据(System.Runtime.Messaging.CallContext的LogicalSetData()和LogicalGetData()方法)。

能够看这几个事例:

private static void Example_ExecutionContext()
{
    CallContext.LogicalSetData("Name", "小红");
    Console.WriteLine("主线程中Name为:{0}", CallContext.LogicalGetData("Name"));

    // 1)   在线程间共享逻辑调用上下文数据(CallContext)。
    Console.WriteLine("1)在线程间共享逻辑调用上下文数据(CallContext)。");
    ThreadPool.QueueUserWorkItem((Object obj) 
        => Console.WriteLine("ThreadPool线程中Name为:\"{0}\"", CallContext.LogicalGetData("Name")));
    Thread.Sleep(500);
    Console.WriteLine();
    // 2)   为了提升性能,取消\恢复执行上下文的流动。
    ThreadPool.UnsafeQueueUserWorkItem((Object obj)
        => Console.WriteLine("ThreadPool线程使用Unsafe异步执行方法来取消执行上下文的流动。Name为:\"{0}\""
        , CallContext.LogicalGetData("Name")), null);
    Console.WriteLine("2)为了提升性能,取消/恢复执行上下文的流动。");
    AsyncFlowControl flowControl = ExecutionContext.SuppressFlow();
    ThreadPool.QueueUserWorkItem((Object obj) 
        => Console.WriteLine("(取消ExecutionContext流动)ThreadPool线程中Name为:\"{0}\"", CallContext.LogicalGetData("Name")));
    Thread.Sleep(500);
    // 恢复不推荐使用ExecutionContext.RestoreFlow()
    flowControl.Undo();
    ThreadPool.QueueUserWorkItem((Object obj) 
        => Console.WriteLine("(恢复ExecutionContext流动)ThreadPool线程中Name为:\"{0}\"", CallContext.LogicalGetData("Name")));
    Thread.Sleep(500);
    Console.WriteLine();
    // 3)   在当前线程上的指定执行上下文中运行某个方法。(通过获取调用上下文数据验证)
    Console.WriteLine("3)在当前线程上的指定执行上下文中运行某个方法。(通过获取调用上下文数据验证)");
    ExecutionContext curExecutionContext = ExecutionContext.Capture();
    ExecutionContext.SuppressFlow();
    ThreadPool.QueueUserWorkItem(
        (Object obj) =>
        {
            ExecutionContext innerExecutionContext = obj as ExecutionContext;
            ExecutionContext.Run(innerExecutionContext, (Object state) 
                => Console.WriteLine("ThreadPool线程中Name为:\"{0}\""<br>                       , CallContext.LogicalGetData("Name")), null);
        }
        , curExecutionContext
     );
}

 

当今的应用程序越来越复杂,我们平日要求运用《异步编制程序:线程概述及利用》中提到的十贰线程技术来增长应用程序的响应速度。那时大家壹再的创造和销毁线程来让应用程序急速响应操作,那往往的创办和销毁无疑会骤降应用程序品质,大家能够引进缓存机制化解那个题材,此缓存机制亟待消除如:缓存的分寸难题、排队执行任务、调度空闲线程、按需成立新线程及销毁多余空闲线程……方今微软曾经为我们提供了现成的缓存机制:线程池

当getstatic指令将race的值取到操作栈的时候,volatile保证了race的值是天经地义的,但是在履行后边的下令的时候,别的的线程大概早就把race的值修改了。

        
线程池原自于对象池,在事无巨细分解明线程池前让大家先来明白下何为对象池。

 

线程池就算为大家提供了异步操作的惠及,不过它不支持对线程池中单个线程的错综复杂控制致使大家有个别情状下会一向动用Thread。并且它对“等待”操作、“撤销”操作、“几次三番”职责等操作相比繁琐,恐怕驱使你从新造轮子。微软也想开了,所以在.NET肆.0的时候参与了“并行职责”并在.NET四.第55中学对其进展立异,想询问“并行职务”的园友能够先看看《(译)关于Async与Await的FAQ》

履行上下文

ThreadPool静态类,为应用程序提供三个由系统管理的支持线程池,从而使你能够集中精力于应用程序义务而不是线程管理。每种进度都有一个线程池,一个Process中只好有二个实例,它在逐一应用程序域(AppDomain)是共享的。

一)         手动清理,即积极调用清理的法子。

  1. 上下文切换中的“上下文”是怎么样?

图片 6图片 7

每当1个线程(开首线程)使用另2个线程(帮忙线程)执行职分时,CLPRADO会将前者的履行上下文流向(复制到)扶助线程(注意这些活动流向是单方向的)。那就保险了支持线程执行的其余操作使用的是同样的平安设置和宿主设置。还打包票了初始线程的逻辑调用上下文可以在扶持线程中选取。

三)         RegisterWaitForSingleObject()方法再次回到2个RegisteredWaitHandle对象的引用。这么些指标标识了线程池正在它上边等待的基石对象。大家能够调用它的Unregister(WaitHandle
waitObject)方法撤除由RegisterWaitForSingleObject()注册的等候操作(即WaitOrTimerCallback委托不再执行)。Unregister(WaitHandle
waitObject)的WaitHandle参数表示成功撤消注册的等待操作后线程池会向此指标发出时域信号(set()),若不想吸收此公告能够传递null。

  1. 鉴于调用了 Abort,线程池线程大校掀起ThreadAbortException。 
    二.
    由张永琛在卸载应用程序域,线程池线程中校引发AppDomainUnloadedException。 
  2. 集体语言运营库或宿主进度将结束线程。

 

View Code

b)        
其实FileStream的异步读写,异步发送接受Web请求,System.Threading.Timer定时器,甚至运用delegate的beginInvoke都会私下认可调用
ThreadPool,也正是说不仅你的代码大概行使到线程池,框架之中也说不定选择到。

在中间,线程池将团结的线程划分工作者线程(扶助线程)和I/O线程。前者用于实践平常的操作,后者专用于异步IO,比如文件和互连网请求,注意,分类并不表明三种线程自身有反差,内部照旧是壹模一样的。

在开发银行线程池时,线程池具有2个停放延迟,用于启用最小空闲线程数,以增进应用程序的吞吐量。

兑现的重大代码

由此,为了进步应用程序品质,大家能够阻碍实施上下文的流淌。当然那惟有在帮衬线程不需求大概不访问上下文音讯的时候才能拓展拦截。

三)         在此时此刻线程上的钦命执行上下文中运作有个别方法。

 

让一个线程不分明地守候2个基本对象进入可用状态,那对线程的内部存款和储蓄器能源来说是一种浪费。ThreadPool.RegisterWaitForSingleObject()为大家提供了1种艺术:在1个水源对象变得可用的时候调用二个方式。

示例

 

当二个“时间片”结束时,假设Windows决定再度调度同二个线程,那么Windows不会履行上下文切换。若是Windows调度了叁个不等的线程,那时Windows执行线程上下文切换。

.NET中上下文太多,作者最后得出的定论是:上下文切换中的上下文专指“执行上下文”。

万1你领悟调用方的库房与在排队职责执行时期实行的持有安检不相干,则还是能够行使不安全的章程
ThreadPool.UnsafeQueueUserWorkItem 和
ThreadPool.UnsafeRegisterWaitForSingleObject。QueueUserWorkItem 和
RegisterWaitForSingleObject
都会捕获调用方的库房,此堆栈将在线程池线程起头推行任务时合并到线程池线程的仓库中。假诺须求举行安检,则必须检查整个堆栈,但它还有着自然的性情费用。使用“不安全的”方法调用并不会提供相对的平安,但它会提供更加好的质量。

参考资料:《CL瑞虎 via C#(第三版)》

  1. 实施上下文类详解

图片 8

在那之中得到到的System.Threading.ExecutionContext正是本小节要说的“执行上下文”。

选拔需注意:

b)        
若使用Thread.CurrentThread.ExecutionContext.CreateCopy()会报“只好复制新近捕获(ExecutionContext.Capture())的上下文”。

驷不及舌达成代码:

 

4)         五个参数

不提议更改线程池中的最大线程数:

  1. 哪天实施“上下文切换”?
public sealed class ExecutionContext : IDisposable, ISerializable
{
    public void Dispose();
    public void GetObjectData(SerializationInfo info, StreamingContext context);

    // 此方法对于将执行上下文从一个线程传播到另一个线程非常有用。
    public ExecutionContext CreateCopy();
    // 从当前线程捕获执行上下文的一个副本。
    public static ExecutionContext Capture();
    // 在当前线程上的指定执行上下文中运行某个方法。
    public static void Run(ExecutionContext executionContext, ContextCallback callback, object state);

    // 取消执行上下文在异步线程之间的流动。
    public static AsyncFlowControl SuppressFlow();
    public static bool IsFlowSuppressed();
    // RestoreFlow  撤消以前的 SuppressFlow 方法调用的影响。
    // 此方法由 SuppressFlow 方法返回的 AsyncFlowControl 结构的 Undo 方法调用。
    // 应使用 Undo 方法(而不是 RestoreFlow 方法)恢复执行上下文的流动。
    public static void RestoreFlow();
}

但实施上下文的复制会招致一定的质量影响。因为实施上下文中包括大批量消息,而采访全体这个新闻,再把它们复制到辅助线程,要消耗成千上万岁月。借使支持线程又接纳了越多地扶持线程,还非得创设和早先化愈多的实践上下文数据结构。

 注意:

  1. 在2个根本构造可用时调用2个办法

 

线程池ThreadPool类详解

可排队到线程池的操作数仅受内部存款和储蓄器的界定;而线程池限制进度中得以而且处于活动状态的线程数(暗中同意景况下,限制每一种CPU 能够选取 2五 个工笔者线程和 一,000 个 I/O 线程(根据机器CPU个数和.net
framework版本的不等,这么些数据只怕会有变化)),全数大于此数量的伸手将维持排队状态,直到线程池线程变为可用。

图片 9图片 10

由此对“对象池”的三个光景认识能帮大家越来越快了解线程池。

 

为制止向线程分配不供给的堆栈空间,线程池遵照一定的岁月距离创设新的空余线程(该区间为半秒)。所以只要最小空闲线程数设置的过小,在短时间内执行大气职务会因为创立新空闲线程的停放延迟导致品质瓶颈。最小空闲线程数私下认可值等于机械上的CPU核数,并且不建议改变最小空闲线程数。

线程池线程中未处理的丰富将告一段落进度。以下为此规则的二种例外情况: 

二)         自动清理,即由此System.Threading.提姆er来完结定时清理。

View Code

 从此图中大家会发现 .NET 与C#
的每一种版本发表都以有一个“大旨”。即:C#一.0托管代码→C#2.0泛型→C#3.0LINQ→C#四.0动态语言→C#5.0异步编制程序。未来本人为新型版本的“异步编制程序”大旨写体系分享,期待您的查看及点评。

  本博文介绍线程池以及其基础对象池,ThreadPool类的利用及注意事项,怎么着排队办事项到线程池,执行上下文及线程上下文字传递递难题…… 

 

几时不使用线程池线程

        
上一小节中谈起:线程池最大线程数设置过大恐怕会促成Windows频仍执行上下文切换,下跌程序品质。对于绝当先四分之二园友不会满足那样的作答,我和您同一也爱不释手“知其然,再知其所以然”。

ExecutionContext
类提供的功用让用户代码能够在用户定义的异步点之间捕获和传导此上下文。公共语言运转时(CLBMWX5)确认保障在托管进程内运维时定义的异步点之间同样地传输
ExecutionContext。

  1. 蹲点Windows上下文切换工具

通过静态方法GetAvailableThreads()再次来到的线程池线程的最大数目和最近活动数量之间的差值,即获取线程池中当前可用的线程数目

         对于对象池的清理平常设计三种艺术:

异步编制程序:使用线程池管理线程

本节到此结束,感激大家的鉴赏。赞的话还请多引入啊 (*^_^*)

一)         WaitOrTimerCallback委托参数,该信托接受二个名称为timeOut的Boolean参数。假若 WaitHandle 在钦定时间内未有收到时域信号(即,超时),则为true,不然为 false。回调方法能够遵照timeOut的值来针对地选拔措施。

②)         为了提高品质,阻止\光复执行上下文的流淌。

图片 11图片 12

 

a)        
将线程池大小设置得太大,可能会招致更频仍的推行上下文切换及深化能源的争用情状。

  1. 线程池线程数
public static class ThreadPool
{
    // 将操作系统句柄绑定到System.Threading.ThreadPool。
    public static bool BindHandle(SafeHandle osHandle);

    // 检索由ThreadPool.GetMaxThreads(Int32,Int32)方法返回的最大线程池线程数和当前活动线程数之间的差值。
    public static void GetAvailableThreads(out int workerThreads
            , out int completionPortThreads);

    // 设置和检索可以同时处于活动状态的线程池请求的数目。
    // 所有大于此数目的请求将保持排队状态,直到线程池线程变为可用。
    public static bool SetMaxThreads(int workerThreads, int completionPortThreads);
    public static void GetMaxThreads(out int workerThreads, out int completionPortThreads);
    // 设置和检索线程池在新请求预测中维护的空闲线程数。
    public static bool SetMinThreads(int workerThreads, int completionPortThreads);
    public static void GetMinThreads(out int workerThreads, out int completionPortThreads);

    // 将方法排入队列以便执行,并指定包含该方法所用数据的对象。此方法在有线程池线程变得可用时执行。
    public static bool QueueUserWorkItem(WaitCallback callBack, object state);
    // 将重叠的 I/O 操作排队以便执行。如果成功地将此操作排队到 I/O 完成端口,则为 true;否则为 false。
    // 参数overlapped:要排队的System.Threading.NativeOverlapped结构。
    public static bool UnsafeQueueNativeOverlapped(NativeOverlapped* overlapped);
    // 将指定的委托排队到线程池,但不会将调用堆栈传播到工作者线程。
    public static bool UnsafeQueueUserWorkItem(WaitCallback callBack, object state);

    // 注册一个等待Threading.WaitHandle的委托,并指定一个 32 位有符号整数来表示超时值(以毫秒为单位)。
    // executeOnlyOnce如果为 true,表示在调用了委托后,线程将不再在waitObject参数上等待;
    // 如果为 false,表示每次完成等待操作后都重置计时器,直到注销等待。
    public static RegisteredWaitHandle RegisterWaitForSingleObject(
            WaitHandle waitObject
            , WaitOrTimerCallback callBack, object state, 
            Int millisecondsTimeOutInterval, bool executeOnlyOnce);
    public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(
              WaitHandle waitObject
            , WaitOrTimerCallback callBack
            , object state
            , int millisecondsTimeOutInterval
            , bool executeOnlyOnce);
    ……
}

 

1)         在线程间共享逻辑调用上下文数据(CallContext)。

c)        
一个选用程序池是贰个独门的长河,拥有三个线程池,应用程序池中得以有三个WebApplication,各类运营在一个单独的AppDomain中,这一个WebApplication公用二个线程池。

线程池线程中的极度

 图片 13

二)         名叫executeOnlyOnce的Boolean参数。传true则意味着线程池线程只举行回调方法一回;若传false则意味内核查象每一回接到实信号,线程池线程都会实行回调方法。等待一个AutoReset伊夫nt对象时,这一个效果进一步有用。

图片 14

2)         使用GetMinThreads()和SetMinThreads()获取和装置最小空闲线程数

 

结果如图:

图片 15

壹)         使用Get马克斯Threads()和Set马克斯Threads()获取和安装最大线程数

一)         CurrentContext       
获取线程正在里面进行的脚下上下文。主要用来线程内部存储数据。

  1. “上下文切换”造成的属性影响

 

除此之外,执行垃圾回收时,CLMurano必须挂起(暂停)全体线程,遍历它们的栈来查找根以便对堆中的对象举行标记,再度遍历它们的栈(有的对象在削减时期发生了移动,所以要更新它们的根),再回复全体线程。所以,减少线程的多寡也会领悟升高垃圾回收器的天性。每一遍使用贰个调节和测试器并遭遇贰个断点,Windows都会挂起正在调试的应用程序中的全数线程,并在单步执行或运营应用程序时回涨全部线程。由此,你用的线程越来越多,调节和测试体验也就越差。

一)        
示例中“在如今线程上的钦定执行上下文中运作有些方法”:代码中务必使用ExecutionContext.Capture()获取当前执行上下文的3个副本