线程池

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

不需要自己创建这样的一个列表。该列表由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. api 签名算法

    <?php define('token', 'tokensecret'); // 定义私钥token /** * 哈希验证签名 */ function hmacSign($array, $tok ...

  2. Luogu P2068 统计和

    P2068 统计和 题目描述 给定一个长度为n(n<=100000),初始值都为0的序列,x(x<=10000)次的修改某些位置上的数字,每次加上一个数,然后提出y (y<=1000 ...

  3. Linux下的find命令

    Linux下find命令在目录结构中搜索文件,并执行指定的操作.Linux下find命令提供了相当多的查找条件,功能很强大.即使系统中含有网络文件系统,find命令在该文件系统中同样有效.在运行一个非 ...

  4. C#学习笔记_08_面向对象

    08_面向对象 面向对象:一种看待问题解决问题的思维方式,着眼点在于找到一个能够帮助我们解决问题的实体,然后委托这个实体来帮我们解决问题:(在面向对象之前你要有一个女朋友,否则代码会经常出现bug) ...

  5. hdu 4081 最小生成树变形

    /*关于最小生成树的等效边,就是讲两个相同的集合连接在一起 先建立一个任意最小生成树,这条边分开的两个子树的节点最大的一个和为A,sum为最小生成树的权值和,B为sum-当前边的权值 不断枚举最小生成 ...

  6. BZOJ1443 游戏game (二分图染色+匈牙利算法)

    先对整幅图进行二分图染色,再跑一遍匈牙利算法.如果最大匹配数=点数*2,那么输出WIN. 对于任何一个非必须在最大匹配上的点,即为所求的点. Program Test375num2; type arr ...

  7. 51Nod——T 1109 01组成的N的倍数

    https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1109 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 ...

  8. oracle 12c之前用sequence 和 trigger来生成自动增长的列

    SQL> create table scott.t1 (id number, val varchar2(8)); Table created. SQL> CREATE SEQUENCE s ...

  9. tabBar颜色改动

    //未点击的颜色 [[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKey ...

  10. [Cypress] Create True end-to-end Tests with Cypress (Smoke test)

    Integration tests let us keep our tests fast and reliable. They also allow us to test scenarios that ...