“線程池”是可以用來在後臺執行多個任務的線程集合。這使主線程可以自由地異步執行其他任務。
線程池通常用於服務器應用程序。每個傳入請求都將分配給線程池中的一個線程,因此可以異步處理請求,而不會佔用主線程,也不會延遲後續請求的處理。
一旦池中的某個線程完成任務,它將返回到等待線程隊列中,等待被再次使用。這種重用使應用程序可以避免爲每個任務創建新線程的開銷。
線程池通常具有最大線程數限制。如果所有線程都繁忙,則額外的任務將放入隊列中,直到有線程可用時才能夠得到處理。
您可以實現自己的線程池,但是通過 ThreadPool 類使用 .NET Framework 提供的線程池更容易一些。
下面的示例使用 .NET Framework 線程池實現單線程下載和多個線程下載的效果:
前臺界面如下:
後臺代碼:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net;
namespace WindowsForm多線程複習
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ThreadStart start = new ThreadStart(DownLoad);
Thread thread = new Thread(start);
thread.Start();
}
private void Mianji(object r)
{
double result = Math.PI * Convert.ToInt32(r) * Convert.ToInt32(r);
this.Invoke(new Action(delegate()
{
MessageBox.Show(result.ToString());
}));
}
private void DownLoad()
{
for (int i = 30000; i < 30010; i++)
{
try
{
using (WebClient client = new WebClient())
{
client.DownloadFile(@"http://job.cnblogs.com/offer/" + i + "/", @"G:\movices\" + i + ".html");
//使用匿名委託的簡寫方式
this.Invoke(new Action(delegate()
{
this.textBox1.AppendText("第" + i + "個帖子已經下載完成\n");
}));
}
}
catch (Exception ex) { }
}
Action action = new Action(Msg);
this.Invoke(action);
}
private void Msg()
{ MessageBox.Show("下載完成"); }
private void button2_Click(object sender, EventArgs e)
{
ParameterizedThreadStart start = new ParameterizedThreadStart(Mianji);
Thread thread = new Thread(start);
thread.Start(5);
}
//使用線程池下載帖子
private void button3_Click(object sender, EventArgs e)
{
//這麼寫其實只是讓線程池啓動了一個線程,沒有利用多線程來操作
WaitCallback wait = new WaitCallback(DownLoadThreadPool);
ThreadPool.QueueUserWorkItem(wait);
}
private void DownLoadThreadPool(object obj)
{
for (int i = 30000; i < 30010; i++)
{
try
{
using (WebClient client = new WebClient())
{
client.DownloadFile(@"http://job.cnblogs.com/offer/" + i + "/", @"g:\movices\" + i + ".html");
//使用匿名委託的簡寫方式
this.Invoke(new Action(delegate()
{
this.textBox1.AppendText("第" + i + "個帖子已經下載完成\n");
}));
}
}
catch (Exception ex) { }
}
Action action = new Action(Msg);
this.Invoke(action);
}
//線程池多現場下載
private void button4_Click(object sender, EventArgs e)
{
for (int i = 30000; i < 30020; i++)
{
WaitCallback wait = new WaitCallback(DownLoadThreadPool2);
ThreadPool.QueueUserWorkItem(wait, i);
}
}
private void DownLoadThreadPool2(object obj)
{
try
{
using (WebClient client = new WebClient())
{
client.DownloadFile(@"http://job.cnblogs.com/offer/" + Convert.ToInt32(obj) + "/", @"g:\movices\" + Convert.ToInt32(obj) + ".html");
//使用匿名委託的簡寫方式
this.Invoke(new Action(delegate()
{
this.textBox1.AppendText("第" + Convert.ToInt32(obj) + "個帖子已經下載完成\n");
}));
}
}
catch (Exception ex) { }
}
}
}
分別實現一下兩種效果:
從以上可以看出使用線程池,並不是先放進去的方法先執行,而是線程池根據實際情況自己來決定先執行哪個方法。還有就是並不是向線程池放進幾個委託,線程池就開啓幾個線程去執行,而是根據cpu以及內存的使用情況,自己決定開啓幾個線程,也許你放進去10個委託,而線程池只開啓了3個線程來執行