在开发中经常会遇到线程的例子,如果某个后台操作比较费时间,我们就可以启动一个线程去执行那个费时的操作,同时程序继续执行。在某些情况下可能会出现多个线程的同步协同的问题,下面的例子就展示了在两个线程之间如何协同工作。 这个程序的思路是共同做一件事情(从一个ArrayList中删除元素),如果执行完成了,两个线程都停止执行。 代码如下: using System; using System.Collections; using System.Collections.Generic; using System.Threading; /// <summary> /// 在开发中经常会遇到线程的例子,如果某个后台操作比较费时间,我们就可以启动一个线程去执行那个费时的操作,同时程序继续执行。在某些情况下可能会出现多个线程的同步协同的问题,下面的例子就展示了在两个线程之间如何协同工作。 /// ///这个程序的思路是共同做一件事情(从一个ArrayList中删除元素),如果执行完成了,两个线程都停止执行。 ///作者:周公 /// 时间:2008-5-17 /// 原发地址:http://blog.csdn.net/zhoufoxcn /// </summary> public class ThreadDemo { private Thread[] threads; private int thrs = 5; private ArrayList stringList; private event EventHandler OnNumberClear;//数据删除完成引发的事件 public static void Main() { ThreadDemo demo = new ThreadDemo(100); demo.Action(); } public ThreadDemo(int number) { Random random = new Random(1000000); stringList = new ArrayList(number); for (int i = 0; i < number; i++) { stringList.Add(i.ToString()); } threads = new Thread[thrs]; for (int i = 0; i < thrs; i++) { threads[i] = new Thread(new ThreadStart(Run)); threads[i].Name = "线程" + (i + 1); } OnNumberClear += new EventHandler(ThreadDemo_OnNumberClear); } /// <summary> /// 开始工作 /// </summary> public void Action() { for (int i = 0; i < thrs; i++) { threads[i].Start(); } } /// <summary> /// 共同做的工作 /// </summary> private void Run() { string stringValue = null; while (true) { Monitor.Enter(this);//锁定,保持同步 stringValue = (string)stringList[0]; Console.WriteLine(Thread.CurrentThread.Name + "删除了" + stringValue); stringList.RemoveAt(0);//删除ArrayList中的元素 if (stringList.Count == 0) { OnNumberClear(this, new EventArgs());//引发完成事件 } Monitor.Exit(this);//取消锁定 Thread.Sleep(5); } } //执行完成之后,停止所有线程 void ThreadDemo_OnNumberClear(object sender, EventArgs e) { Console.WriteLine("执行完了,停止了所有线程的执行。"); for (int i = 0; i < thrs; i++) { threads[i].Abort(); } } }
用例:
using PMS.DBEntity; using System; using System.Web; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.IO; namespace PMS.Convert.PDF { public struct FileInfo { public int fileid; public string filepath; } public class ConvertSwf { static Queue<FileInfo> filelist = new Queue<FileInfo>(); private static string rootpath = HttpContext.Current.Server.MapPath("~/"); private static Thread t = null; private static string conn = ""; public static void LoadQueue(int classid, string _conn) { conn = _conn; using (var entity = new PMSEntities(conn)) { DALContent dal = new DALContent(); var fileinfo = (from p in entity.jcms_normal_content where p.ClassId == classid && p.IsPass == 1 && p.CustomField05.Substring(0, 10) == "pdf" && p.CustomField03 != null select p); if (!fileinfo.Any()) { return; } foreach (var item in fileinfo) { filelist.Enqueue(new FileInfo { fileid = item.Id, filepath = rootpath + "" + item.CustomField03.Remove(0, 1) }); item.CustomField05 = "convet"; } entity.SaveChanges(); } } public static void ExecTreade() { try { if (t == null) { t = new Thread(Run); t.Start(); } if (!t.IsAlive) { t = new Thread(Run); t.Start(); } } catch (Exception) { throw; } } public static string sourcefile = ""; static string outfile = ""; static void Run() { Pdf2Swf pdf2swf = new Pdf2Swf(); string saveName = ""; string extension = ""; string outfile = ""; int id = 0; using (var entity = new PMSEntities(conn)) { while (filelist.Count > 0) { FileInfo f = filelist.Dequeue(); ; sourcefile = f.filepath; id = f.fileid; saveName = Path.GetFileName(sourcefile); extension = Path.GetExtension(sourcefile).ToLower(); saveName = saveName.Substring(0, saveName.Length - extension.Length); outfile = Path.GetDirectoryName(sourcefile) + "/" + saveName + "_%.swf"; try { pdf2swf.PDFConvertToSWF(sourcefile, outfile); } catch (Exception ex) { throw ex; continue; } var content = entity.jcms_normal_content.SingleOrDefault(p => p.Id == id); if (File.Exists(outfile.Replace("_%", "_1"))) { content.CustomField04 = "/" + outfile.Replace(rootpath, "").Replace("_%", "_[*,0]"); content.CustomField05 = "complete"; entity.SaveChanges(); } else { content.CustomField04 = ""; content.CustomField05 = "error"; entity.SaveChanges(); } } } t.Abort(); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MyProject.Common { public static class TaskUility { static TaskUility() { Run(); } /// <summary> /// 开启线程 /// </summary> public static void Run() { taskThread.Start(); } //线程互斥 private static readonly object _syncObject = new object(); //初始化队列 private static Queue<Action> taskList = new Queue<Action>(); //初始化线程 private static Thread taskThread = new Thread(RunTask); public static void Add(Action action) { lock (_syncObject) { // 把任务加入队列中 taskList.Enqueue(action); } } private static void RunTask() { while (true) { Action action = null; lock (_syncObject) { //当队列有数据,出队. if (taskList.Count > 0) { action = taskList.Dequeue(); // 执行action if (action != null) { action(); } } } Thread.Sleep(5); } } } }
现在有100个任务,需要多线程去完成,但是要限定同时并发数量不能超过5个。
写个简单的类就完成了需求
public class LimitedTaskFactoryEx { private readonly int _maxThreadCount = 5; public LimitedTaskFactoryEx(int maxThreadCount) { _maxThreadCount = maxThreadCount; Start(); } private readonly SafedQueue<Action> _actionQueue = new SafedQueue<Action>(); public void StartNew(Action action) { _actionQueue.Enqueue(action); } private void Start() { for (int i = 0; i < _maxThreadCount; i++) { var thread = new Thread(new ThreadStart(InternalRun)); thread.Start(); } } private void InternalRun() { while (true) { var action = _actionQueue.Dequeue(); if (action != null) { action(); } else { Thread.Sleep(30); } Console.WriteLine(string.Format("Index: {0}, TaskId: {1}, ThreadId: {2}.", 1, Task.CurrentId, Thread.CurrentThread.ManagedThreadId)); } } }
定义个线程池ThreadPool
然后可以指定最小线程数量和最大线程数量,分别定义成0和5就行了
然后把方法用线程池执行
public class MyTaskList { public List<Action> Tasks = new List<Action>(); public void Start() { for (var i = 0; i < 5; i++) StartAsync(); } public event Action Completed; public void StartAsync() { lock (Tasks) { if (Tasks.Count > 0) { var t = Tasks[Tasks.Count - 1]; Tasks.Remove(t); ThreadPool.QueueUserWorkItem(h => { t(); StartAsync(); }); } else if (Completed != null) Completed(); } } }
测试
var rnd = new Random(); var lst = new MyTaskList(); for (var i = 0; i < 100; i++) { var s = rnd.Next(10); var j = i; var 测试任务 = new Action(() => { Console.WriteLine(string.Format("第{0}个任务(用时{1}秒)已经开始", j, s)); Thread.Sleep(s * 1000); Console.WriteLine(string.Format("第{0}个任务(用时{1}秒)已经结束", j, s)); }); lst.Tasks.Add(测试任务); } lst.Completed += () => Console.WriteLine("____________________没有更多的任务了!"); lst.Start();
参考文摘:
如何简易的提高吞吐量 http://www.cnblogs.com/selfteam/p/4912602.html
C#任务队列的实现代码 http://blog.csdn.net/zwc0910/article/details/8127268 http://blog.csdn.net/tonnychu/article/details/46531001
多线程调用 ThreadPool.QueueUserWorkItem http://bbs.csdn.net/topics/390819824
为什么要放弃使用Thread.Sleep http://www.cnblogs.com/fujet/p/4337392.html?utm_source=tuicool&utm_medium=referral