线程池,千万注意,原来很多人都在错用

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行。

[C#线程池]

场景:以下是C# winform写的一个线程池示例程序。窗体上,分别拖放一个开始和停止按钮,单击开始按钮,for寻觅模拟7000个任务队列,在线程池运行过程中,可以点击停止按钮,来结束线程池所有任务,这里借助CancellationTokenSource对象,来实现线程池的停止。

开始前,请大家看以下代码,有什么问题?这里以C# Winform的形式,向大家展现以下代码:

1、第一种:这是开始按钮单击事件的代码

btnStart.Enabled = false;
            isStop = false;
            listCancels.Clear();//清空
            cancelToken.Dispose();
            cancelToken = new CancellationTokenSource();
            System.Threading.ThreadPool.SetMaxThreads(4, 2);
            System.Threading.ThreadPool.SetMinThreads(2, 1);
            for (int i = 0; i < 7000; i++)
            {
                System.Threading.ThreadPool.QueueUserWorkItem((state) =>
                {
                    while (true)
                    {
                        lock (locker)
                        {
                            if (isStop) { break; };
                            if (cancelToken.IsCancellationRequested) { break; }
                        }

                        int works = 0, maxwork = 0;
                        int port = 0, maxport = 0;

                        System.Threading.ThreadPool.GetAvailableThreads(out works, out port);
                        System.Threading.ThreadPool.GetMaxThreads(out maxwork, out maxport);

                        lblStatus.BeginInvoke(new Action(() =>
                        {
                            lblStatus.Text = System.Threading.Thread.CurrentThread.ManagedThreadId + ":" + Guid.NewGuid();

                        }));
                        System.Threading.Thread.Sleep(100);
                    }

                });
            }

2、第二种:看出有何不同了吗,好像差不多,都很正常对吧

 btnStart.Enabled = false;
            isStop = false;
            listCancels.Clear();//清空
            cancelToken.Dispose();
            cancelToken = new CancellationTokenSource();
            System.Threading.ThreadPool.SetMaxThreads(4, 2);

            for (int i = 0; i < 7000; i++)
            {
                System.Threading.ThreadPool.QueueUserWorkItem((state) =>
                {
                    while (true)
                    {
                        lock (locker)
                        {
                            if (isStop) { break; };
                            if (cancelToken.IsCancellationRequested) { break; }
                        }

                        int works = 0, maxwork = 0;
                        int port = 0, maxport = 0;

                        System.Threading.ThreadPool.GetAvailableThreads(out works, out port);
                        System.Threading.ThreadPool.GetMaxThreads(out maxwork, out maxport);

                        lblStatus.BeginInvoke(new Action(() =>
                        {
                            lblStatus.Text = System.Threading.Thread.CurrentThread.ManagedThreadId + ":" + Guid.NewGuid();

                        }));
                        System.Threading.Thread.Sleep(100);
                    }

                });
            }

3、第三种:

 btnStart.Enabled = false;
            isStop = false;
            listCancels.Clear();//清空
            cancelToken.Dispose();
            cancelToken = new CancellationTokenSource();
            System.Threading.ThreadPool.SetMinThreads(2, 1);
            System.Threading.ThreadPool.SetMaxThreads(4, 2);

            for (int i = 0; i < 7000; i++)
            {
                System.Threading.ThreadPool.QueueUserWorkItem((state) =>
                {
                    while (true)
                    {
                        lock (locker)
                        {
                            if (isStop) { break; };
                            if (cancelToken.IsCancellationRequested) { break; }
                        }

                        int works = 0, maxwork = 0;
                        int port = 0, maxport = 0;

                        System.Threading.ThreadPool.GetAvailableThreads(out works, out port);
                        System.Threading.ThreadPool.GetMaxThreads(out maxwork, out maxport);

                        lblStatus.BeginInvoke(new Action(() =>
                        {
                            lblStatus.Text = System.Threading.Thread.CurrentThread.ManagedThreadId + ":" + Guid.NewGuid();

                        }));
                        System.Threading.Thread.Sleep(100);
                    }

                });
            }

如果没有看出以上三段代码有何不同,那就一定要看看下面的内容。

接下来,我们借助操作系统的任务管理器,来及时监测Winform进程所进行的线程数。

如果,是第一种写法,我们来看看:

结果,并不像我们预想的那样,即使如此,线程数还在一路飙升,不一会儿竟达到两百多个线程,这是为何?

第二种,只不过是比第一种少些了一行System.Threading.ThreadPool.SetMinThreads(2, 1);的代码,结果,

好像没有什么变化,线程池仍然一路飙升,直到UI线程出现假死。

就在我写这两段博客的瞬间,看看任务管理器的情况吧:

什么,线程数601?暂不说它是否精确,但此刻,程序是很不正常的在运行。

第三种,是在第一种基础上,调整了两行代码的顺序,恰是这两行代码,让我们正视了之前线程池误区。也改变了结果。以第三种方式,我将程序运行6个多小时,一夜不关,程序依然运行平稳,线程数依然保持在较稳的水平。

原来,顺序真的很重要。经常看到网上有关C#线程池用法的博客,当我们看到,上来都写

System.Threading.ThreadPool.SetMaxThreads(4, 2);这行代码时,我们切记要注意了。当任务量小的时候,这种问题并不明显,依然能很好的完成工作。但是,像我以上的例子,庞大任务队列加入线程池,每个任务又以漫长的运行周期在运行。那把上面那个例子,搬上去看看,这种写法必死,切记。

使用C#线程池的时候,一定要先设置 System.Threading.ThreadPool.SetMinThreads(2, 1);,然后再设置

System.Threading.ThreadPool.SetMaxThreads(4, 2);,这才是C#线程池正确的用法。

最后给大家介绍一个关键词volatile,不知道的朋友,可以了解下。想要了解更多多线程池方面的信息,请访问http://www.lichaoqiang.com/

时间: 2024-10-09 20:46:21

线程池,千万注意,原来很多人都在错用的相关文章

上传伪技术~很多人都以为判断了后缀,判断了ContentType,判断了头文件就真的安全了。是吗?

今天群里有人聊图片上传,简单说下自己的经验 0.如果你的方法里面是有指定路径的,记得一定要过滤../,比如你把 aa文件夹设置了权限,一些类似于exe,asp,php之类的文件不能执行,那么如果我在传路径的时候,前面加了一个../呢,这样这种服务器端的限制就跳过了.(DJ音乐站基本上都有这个问题,以及用某编辑器的同志) 1.常用方法:这种就是根据后缀判断是否是图片文件,需要注意的是这种格式:文件:1.asp;.jpg  1.asp%01.jpg  目录: 1.jpg/1.asp 1.jpg/1.

为什么知乎上很多人都反对创业?(上战场的士兵如果先拿枪打打靶练练枪法,研究研究战术之后,战损比肯定要更好看一点)

为什么知乎上很多人都反对创业? 经常看到一些排名靠前的答案,内容无非规劝他人不要创业,要脚踏实地,认为党和国家大众创业万众创新的政策方针都是胡扯?难道知乎上的知识分子们竟比国家的智囊更有远见?还是他们的认识层次达不到? 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:唐缺链接:https://www.zhihu.com/question/37559307/answer/72755062来源:知乎 -------------------------------------

很多人都在埋怨没有遇到好的团队,但好的团队不可能凭空出现,一流的团队不能仅靠团队成员努力,作为Leader,要有可行的规划,并坚定地执行、时势地调整(转)

<西游记>中的唐僧团队历经千难万险,终于求得真经,目标明确.分工合理为这支队伍最终走向成功奠定了基础.唐僧从一开始,就为这个团队设定了西天取经的目标,虽然经历各种挫折与磨难,但目标从未动摇.悟空探路.八戒牵马.沙僧挑担,几位徒弟一起肩负着保护唐僧的任务.虽然性格迥异.各有缺点,但目标分解合理及成员分工合作,最终风雨同舟,取得真经. <西游记>的故事引申到实际团队技术管理中,也一样有借鉴意义,本文作者为CTO俱乐部会员.湖北同城一家网络科技有限公司开发总监杨斌,他结合自己多年经历谈谈

很多人都说给孩子吃零食不好,这点我也非常肯定

很多人都说给孩子吃零食不好,这点我也非常肯定,但是任何事物也都不是绝对.零食虽然通常都会含有大量的糖分.添加剂或者是油脂等等,对儿童的身体发育相当不利http://www.ximalaya.com/zhubo/27345094/ http://www.ximalaya.com/zhubo/27345095/ http://www.ximalaya.com/zhubo/27345096/ http://www.ximalaya.com/zhubo/27345098/ http://www.xima

百度一下,你就知道很多人都读过纳兰性德这首词,是的,如果“人生若只如初见,何事秋风悲画善”。多么美好的词,可惜那些当初的美好,又怎能抵挡的了岁月的无情

很多人都读过纳兰性德这首词,是的,如果“人生若只如初见,何事秋风悲画善”.多么美好的词,可惜那些当初的美好,又怎能抵挡的了岁月的无情. 如果说初见总是那么叩人心弦,荡气回肠,那么携手走过的风花雪月,又怎能如此戚绝心肠.然而世事总是将一颗如梦的心扉,敲打的魂飞魄散,如斯薄凉. 很多年前,便喜欢上这么两个字——惜缘.总觉得,人与人的相遇是多么的不容易,是的,有人说:“五百年才换来今生的擦肩而过”,如若有缘相识,相知,相处,又是何其珍贵.终是如此,还是有许多缘分刹那间谢尽芳华. 一路走来,不知演绎了多

这个季节吃茄子能治疗7种疾病,很多人都不知道!

这个季节吃茄子能治疗7种疾病,很多人都不知道! 2016-04-26 都市报道扩大版 茄子的功效有什么?茄子含有维生素E,有防止出血和抗衰老功能,常吃茄子,可使血液中胆固醇水平不致增高,对延缓人体衰老具有积极的意义.下面盘点一下茄子的7大功效,或许你会对茄子刮目相看. 1.抗衰老 茄子含有维生素E,有防止出血和抗衰老功能,常吃茄子,可使血液中胆固醇水平不致增高,对延缓人体衰老具有积极的意义. 2.清热解毒 用于热毒痈疮.皮肤溃疡.口舌生疮.痔疮下血.便血.衄血等. 中医学认为,茄子属于寒凉性质的

或许很多人都觉得如此惊为天人的美貌不可能是天生的

[导读]说到混血,大家很自然就会联想到帅哥美女,在帅哥美女扎堆的娱乐圈,自然也不乏混血美女,或许很多人都不明白她们为什么美得那么有特点,原来因为她们是混血,下面就看看娱乐圈最惊艳的混血女星有哪些? Angelababy 最近这几年Angelababy可谓红得发紫,在两岸三地甚至东南亚的荧幕荧屏和广告牌上经常都能看到她的身影,但关于她整容的质疑也一直挥之不去,或许很多人都觉得如此惊为天人的美貌不可能是天生的.原来她有着四分之一德国血统,就像一个精致的洋娃娃,有着一张无可挑剔的面孔,小巧却挺拔的鼻梁

mg幸运双星游戏5个星技巧、攻略、很多人都不曾注意到的必胜规律

说起mg幸运双星我想大家都了解,mg幸运双星是一款旋转类的电子游艺,很多人都认为这个mg幸运双星是靠运气,但是我今天要说的是mg幸运双星是有他的规律的,如果你认为mg幸运双星只是单单凭运气就能打好的话,那你就是大错特错了.mg幸运双星肯定还是有一些打法的,要不然每次都看运气的话是绝对不长远的.其实打这个mg幸运双星没有想象中的那么难,可能很多人都不清楚的就是,mg幸运双星就是一个慢热型的,前期的累积可以有点久,但是一旦出了就是很大的,但是并不代表每个人都能领会其中的精髓.这就是mg幸运双星这么简

[转帖](区块链补习班)ERC20很多人都听过,但ERC是什么你真的了解吗?

(区块链补习班)ERC20很多人都听过,但ERC是什么你真的了解吗? http://baijiahao.baidu.com/s?id=1600948969290990883&wfr=spider&for=pc 区块链福利社 发布时间:18-05-2012:15 ▌今日币价 Btc$8505/ Eth$707/Eos$12.94 本文不介绍技术代码相关,具体代码可在文末自行下载学习,为了方便阅读下文,特此做几个定义的解释: 可替代性通证(fungible token):在本文指的是基于区块链