线程池

创建线程需要时间,如果有不同的小任务要完成,就可以事先创建许多线程,在应完成这些任务时发出请求。这个线程数最好在需要更多线程时增加,在需要释放资源时减少。

不需要自己创建这样的一个列表。该列表由ThreadPool类托管。该类会在需要时增加线程池中线程数,直到最大的线程数。

  • 可以指定创建线程池时立即启动的最小线程数,以及线程池中可用的最大线程数。
  • 如果更多的作业要处理,线程池中的线程个数也到了极限,最新的作业就要排队,且必须等待线程完成其作业。
  • 线程池中的线程都是后台线程,不能把入池的线程改为前台线程。
  • 不能给入池的线程设置优先级和名字。
  • 对于COM对象,入池的所有线程都是多线程单元线程。许多COM对象都需要单线程单元线程。
  • 入池的线程只能用于时间比较短的任务。如果线程要一直运行,就应该使用Thread类创建一个线程。
static void Main()
{
int nWorkerThreads;
int nCompletionPorThreads;
ThreadPool.GetMaxThreads(out nWorkerThreads, out nCompletionPorThreads);
//ThreadPool.SetMaxThreads(500, 500);
lib.print("Max worker threads : " + nWorkerThreads);
lib.print("I/O completion threads: " + nCompletionPorThreads); for(int i=; i<; i++)
{
ThreadPool.QueueUserWorkItem(JobForAThread);//将方法排入队列以便执行。 此方法在有线程池线程变得可用时执行。
}
Thread.Sleep();
} static void JobForAThread(object state)
{
for(int i = ; i<; i++)
{
Console.WriteLine("loop {0}, running inside pooled thread {1}", i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep();
}
}

示例应用程序首先要读取工作线程和I/O线程的最大线程数,把这些信息写入控制台中。接着在for循环中,调用Thread.QueueuserWorkItm()方法,传递一个WaitCallback类型的委托,把JobForAThread()方法赋予线程池中的线程。

线程池收到这个请求后,就会从池中选择一个线程,来调用该方法。如果线程池还没有运行,就会创建一个线程池,并启动第一个线程。如果线程池己经在运行,且有一个空闲线程来完成该任务,就把该作业传递给这个线程。

异步委托

创建线程最简单的方式是定义一个委托,然后异步调用它。

委托使用线程池完成异步任务,当没有前台线程运行时,异步委托将直接结束。

static void Main(string[] args)
{
Action action = new Action(() =>
{
for(int i=; i<; i++)
{
lib.put(".");
Thread.Sleep();
}
}); AsyncCallback calback = (IAsyncResult result) =>
{
Thread.Sleep();
lib.print(result.AsyncState);
};
var rs = action.BeginInvoke(calback, "Begin Invoke");//如此,便启动了异步委托。下面用不同方法等待异步委托完成。 //方法一,用EndInvoke方法,该方法会一直等待,直到委托完成任务为止。
action.EndInvoke(rs); //方法二,使用IAsyncResult相关联的等待句柄。使用AsyncWaitHandle属性可以访问等待句柄。
//这个属性返回一个WaitHandle类型对象,它可以等待委托线程完成其任务。参数是最长等待时间,
//-1表示无限等待。如果当前实例收到信号,则返回为 true;否则为 false。
rs.AsyncWaitHandle.WaitOne(); //方法三,不断检查
while (true)
{
if (!rs.IsCompleted)
{
Thread.Sleep();
}
else
{
break;
}
} //因为callback最终是异步线程回调的,所以,如果直接退出,callback将无法打印出Begin Invoke。
Thread.Sleep();
}

任务

System.Threading.Tasks包含的类抽象出了线程功能,在后台使用ThreadPool。任务表示应完成的某个单元工作,这个单元工作可以在单独的线程中运行,也可以以同步方式启动一个任务,这需要等待主线程。使用任务不仅可以获得一个抽象层,还可以对底层线程进行很多控制。

  • 启动任务

可以使用实例化的TaskFactory类,在其中把TaskMethod()方法传递给StarNew()方法,就会立刻启动任务。也可以使用Task类的构造函数。实例化Task对象时,任务不会立即运行,而是指定Created状态。接着调用Task类的Start()方法,来启动任务。使用Task类时,还可以调用TunSynchronously()方法。

static void Main(string[] args)
{
Task t1 = new Task(DoOnFirst);
t1.Start(); TaskFactory tf = new TaskFactory();
Task t2 = tf.StartNew(DoOnFirst); Task t3 = Task.Factory.StartNew(DoOnFirst); Task.WaitAll(t1, t2, t3);
}
static void DoOnFirst()
{
lib.print("Task.CurrentId :" + Task.CurrentId);
lib.print("-----------");
Thread.Sleep();
}
  • 连续的任务

连续任务通过在任务上调用ContinueWith()方法类定义。不带TaskContinuationOptions参数,则无论前一个任务是如何结束的,后续任务都启动。也可以用TaskContinuationOptions枚举中的值,来指定连续任务在什么情况下启动。

static object o = new object();
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
cts.Token.Register(()=>{
Console.WriteLine("*** token canceled.");
}); Task t1 = new Task(DoOnFirst, cts.Token);
//t1完成的情况下启动t2
Task t2 = t1.ContinueWith(DoOnSecond, TaskContinuationOptions.OnlyOnRanToCompletion);
//t1被取消的情况下启动t3
Task t3 = t1.ContinueWith(DoOnThird, TaskContinuationOptions.OnlyOnCanceled);
try
{
t1.Start();
//cts.Cancel( ); //打开注释,取消了t1,将执行DoOnThird。
}
catch
{
lib.print("t1.IsCanceled : " + t1.IsCanceled);
}
Console.ReadKey();
}
static void DoOnFirst()
{
lock (o)
{
lib.print("Task.CurrentId :" + Task.CurrentId);
lib.print("-----------"); Thread.Sleep();
}
}
static void DoOnSecond(Task t)
{
lock (o)
{
lib.print("task " + t.Id + " finished.");
lib.print("this task id " + Task.CurrentId);
lib.print("-----------"); Thread.Sleep();
}
}
static void DoOnThird(Task t)
{
lock (o)
{
lib.print("task " + t.Id + " Canceld.");
lib.print("this task id " + Task.CurrentId);
lib.print("-----------"); Thread.Sleep();
}
}

任务层次结构

任务也可以构成一个层次结构。一个任务启动一个新任务时,就启动了一个父/子层次结构。

任务的结果

任务结束时,可以把一些有用的状态信息写到共享对象中。也可以使用返回结果的任务返回这些信息。

static void Main(string[] args)
{
Task<int> t1 = new Task<int>((object o)=>{return ;}, "");
t1.Start();
t1.Wait();
lib.print(t1.Result); Task t = new Task(DoParentTask);
t.Start();
}

C# 多线程系列(四)

C# 多线程系列(三)的更多相关文章

  1. java多线程系列(三)---等待通知机制

    等待通知机制 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解 ...

  2. (Java多线程系列三)线程间通讯

    Java多线程间通讯 多线程之间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同. 1.使用wait()和notify()方法在线程中通讯 需求:第一个线程写入(input)用户,另一个线程 ...

  3. Java多线程系列三——实现线程同步的方法

    两种实现线程同步的方法 方法 特性 synchronized 不需要显式地加解锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 ...

  4. 【Java多线程系列三】实现线程同步的方法

    两种实现线程同步的方法 方法 特性 synchronized  不需要显式的加锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁  ...

  5. 多线程系列三:Lock和Condition

    有了synchronized为什么还要Lock? 因为Lock和synchronized比较有如下优点 1. 尝试非阻塞地获取锁 2. 获取锁的过程可以被中断 3. 超时获取锁 Lock的标准用法 p ...

  6. Java多线程系列十——BlockingQueue

    参考资料:http://ifeve.com/java-synchronousqueue/http://www.cnblogs.com/jackyuj/archive/2010/11/24/188655 ...

  7. Java多线程系列--“JUC线程池”04之 线程池原理(三)

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基 ...

  8. java 多线程系列---JUC原子类(三)之AtomicLongArray原子类

    AtomicLongArray介绍和函数列表 在"Java多线程系列--“JUC原子类”02之 AtomicLong原子类"中介绍过,AtomicLong是作用是对长整形进行原子操 ...

  9. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...

随机推荐

  1. Vector 二维数组 实现

    1.C++实现动态二维数组 int **p; p = ]; //注意,int*[10]表示一个有10个元素的指针数组 ; i < ; ++i) { p[i] = ]; } 2.利用指针数组实现二 ...

  2. 新版本的molar mass(uva-1586)明明debug过了,各种测试还是WA真是气死我了

    #include <bits/stdc++.h> using namespace std; double trans(string a) { stringstream ss; ss< ...

  3. 数据类型与变量(Python学习笔记01)

    数据类型与变量 Python 中的主要数据类型有 int(整数)/float(浮点数).字符串.布尔值.None.列表.元组.字典.集合等. None 每个语言都有一个专门的词来表示空,例如 Java ...

  4. PAT 1047. Student List for Course

    Zhejiang University has 40000 students and provides 2500 courses. Now given the registered course li ...

  5. net Core 中定时任务的设置

    接下来的任务 采用定时任务的需求场景: 每天的数据整理,比如库存,每天的零散数据的统计,定时提醒,定时提醒到期未完成的任务-.... 1.采用的第三方类库: quartz 2文档地址:http://w ...

  6. 《hello-world》第八次团队作业:Alpha冲刺-Scrum Meeting 1

    项目 内容 这个作业属于哪个课程 2016级计算机科学与工程学院软件工程(西北师范大学) 这个作业的要求在哪里 实验十二 团队作业8:软件测试与Alpha冲刺 团队名称 <hello--worl ...

  7. Huawei-R&S-网络工程师实验笔记20190525-设备登录、VRP基本配置、文件系统

    >Huawei-R&S-网络工程师实验笔记20190525-设备登录.VRP基本配置.文件系统(环回接口.telnet远程.AAA登录.命令行.时钟.banner.文件目录) >& ...

  8. Spring Boot开发HTTPS协议的REST接口

    Spring Boot开发HTTP的REST接口流程在前文中已经描述过,见<SpringBoot开发REST接口>. 如需要支持HTTPS,只需要在如上基础上进行设置.修改/resourc ...

  9. readl()和writel()

    writel() 往内存映射的 I/O 空间上写数据,wirtel() I/O 上写入 32 位数据 (4字节). 原型: 引用 #include <asm/io.h> void writ ...

  10. EasyUI 在textbox里面输入数据敲回车后查询和普通在textbox输入数据敲回车的区别

    EasyUI实现回车键触发事件 $('#id').textbox('textbox').keydown(function (e) { if (e.keyCode == 13) { alert('ent ...