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

简介: 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行。[C#线程池]场景:以下是C# winform写的一个线程池示例程序。

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

[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/

目录
相关文章
|
11月前
|
缓存 Java 应用服务中间件
线程池的10个坑你都遇到过吗
日常开发中,为了更好管理线程资源,减少创建线程和销毁线程的资源损耗,我们会使用线程池来执行一些异步任务。但是线程池使用不当,就可能会引发生产事故。大家看完肯定会有帮助的~
172 0
|
9天前
|
Java
线程池的实现
线程池的实现
12 0
|
1月前
|
缓存 算法 Java
|
10月前
|
Java
线程池总结
线程池总结
46 0
|
存储 Java 测试技术
13.一文彻底了解线程池
大家好,我是王有志。线程池是Java面试中必问的八股文,涉及到非常多的问题,今天我们就通过一篇文章,来彻底搞懂Java面试中关于线程池的问题。
372 2
13.一文彻底了解线程池
|
10月前
|
监控 Java
线程池的讲解和实现
线程池的讲解和实现
|
11月前
|
缓存 Java 调度
线程池的介绍
线程池的介绍
|
11月前
|
前端开发 Java 调度
|
11月前
|
Java 数据库连接 容器
关于线程池
关于线程池
63 0
|
缓存 算法 Java
线程池和使用
线程池是一种用于管理和复用线程的机制。在多线程应用程序中,线程的创建和销毁需要消耗大量的系统资源,而线程池可以通过预先创建一定数量的线程,然后将任务分配给这些线程来避免频繁地创建和销毁线程,从而提高应用程序的性能和效率。线程池还可以控制并发线程的数量,避免过多的线程竞争资源导致的性能下降和系统崩溃。线程池是多线程编程中常用的一种技术,被广泛应用于各种类型的应用程序中。
60 0
线程池和使用