线程池

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

不需要自己创建这样的一个列表。该列表由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. sublime右键菜单,anaconda设置

    1.sublime_addright.inf [Version]Signature="$Windows NT$" [DefaultInstall]AddReg=SublimeTex ...

  2. 关于panda中dataframe的与&运算*(stackoverflow高票答案)

    85 down vote favorite 31 What explains the difference in behavior of boolean and bitwise operations ...

  3. cmake更新版本简记

    问题描述: 由于需求,要在服务器上安装ANTs(Advanced Normalization Tools).然而最新版的ANTs需要下载源码并用cmake编译, 于是根据https://github. ...

  4. 9.boost权重控制

    主要知识点: 学会在should中使用boost进行权重控制     假如现在有一个需求:要把should中某些字段优先显示, 1.不加boost权重控制 GET /forum/article/_se ...

  5. 基本数据类型:字符串(str)

    一.字符串的定义和创建 字符串是一个有序的字符的集合,用于存储和表示基本的文本信息,' '或'' ''或''' '''中间包含的内容称之为字符串,总之加了引号的字符都被认为是字符串! 创建: > ...

  6. 联想小新Air 15 安装黑苹果macOS High Sierra 10.13.6过程

    联想小新Air 15 安装黑苹果全过程 本文参考:https://blog.csdn.net/qq_28735663/article/details/80634300 本人是联想小新AIr 15 , ...

  7. 【Codeforces 1114C】Trailing Loves (or L'oeufs?)

    [链接] 我是链接,点我呀:) [题意] 问你n!的b进制下末尾的0的个数 [题解] 证明:https://blog.csdn.net/qq_40679299/article/details/8116 ...

  8. 【郑轻邀请赛 F】 Tmk吃汤饭

    [题目链接]:https://acm.zzuli.edu.cn/zzuliacm/problem.php?id=2132 [题意] [题解] 很容易想到用队列来模拟; 这个队列维护的是正在煮的4个人煮 ...

  9. Contest Round #451 (Div. 2)F/Problemset 898F Restoring the Expression

    题意: 有一个a+b=c的等式,去掉两个符号,把三个数连在一起得到一个数 给出这个数,要求还原等式,length <= 1e6 三个数不能含有前导0,保证有解 解法: 铁头过题法,分类然后各种判 ...

  10. JavaSE 学习笔记之多态(七)

    多 态:函数本身就具备多态性,某一种事物有不同的具体的体现. 体现:父类引用或者接口的引用指向了自己的子类对象.//Animal a = new Cat(); 多态的好处:提高了程序的扩展性. 多态的 ...