线程开启的四种方式(异步委托,thread类,线程池,任务)

文章框架
线程开启方式
--1通过异步委托实现线程
----1.1定义线程
----1.2检测委托线程结束,通过while循环,等待句柄,函数回调

--2通过thread类开启线程
----2.1定义线程
----2.2如何传递参数
----2.3线程优先级
----2.4线程控制

--3、通过线程池开启线程

--4、通过任务开启线程
----4.1通过任务或任务工厂
----4.2连续任务
----4.3任务的层次结构
----4.4任务的执行结果

线程开启方式

1、通过异步委托实现线程

1.1定义线程

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Text10
{
    class Program
    {
        static int Test(int n, string s)
        {
            Console.WriteLine(s + n);
            return 10;
        }
        static void Main(string[] args)
        {
            Func<int, string, int> func= Test;
            func.BeginInvoke(1,"bey",null,null);
            Console.WriteLine("hello,world!!!");
            Console.ReadLine();
        }
    }
}
image.png
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text10
{
    class Program
    {
        static int Test(int n, string s)
        {
            Console.WriteLine(s + n);
            Thread.Sleep(100);//让当前线程休眠
            return 10;
        }
        static void Main(string[] args)
        {
            Func<int, string, int> func= Test;
            IAsyncResult ar= func.BeginInvoke(1,"bey",null,null);
            Console.WriteLine("hello,world!!!");
            while (ar.IsCompleted == false)//判断当前线程是否完成
            {
                Console.Write("-");
            }
            int res=func.EndInvoke(ar);//取得异步进程的返回值
            Console.ReadLine();
        }
    }
}

image.png

1.2检测委托线程结束,通过等待句柄,函数回调

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text10
{
    class Program
    {
        static int Test(int n, string s)
        {
            Console.WriteLine(s + n);
            Thread.Sleep(100);//让当前线程休眠
            return 10;
        }
        static void Main(string[] args)
        {
            //Func<int, string, int> func= Test;
            //IAsyncResult ar= func.BeginInvoke(1,"bey",null,null);
            //Console.WriteLine("hello,world!!!");
            ////方法一 while循环
            //while (ar.IsCompleted == false)//判断当前线程是否完成
            //{
            //    Console.Write("-");
            //}
            //int res=func.EndInvoke(ar);//取得异步进程的返回值

            ////方法二:等待句柄
            //bool isEnd=ar.AsyncWaitHandle.WaitOne(1000);//1000毫秒代表超时时间
            //if (isEnd)
            //{
            //    int res = func.EndInvoke(ar);
            //    Console.WriteLine(res);
            //}

            ////方法三:函数回调
            //Func<int, string, int> func = Test;
            //IAsyncResult ar = func.BeginInvoke(1, "bey", CallBack, func);

            //简便写法lambda表达式
            Func<int, string, int> func = Test;
            func.BeginInvoke(1, "bey", (ar)=> 
            {
                int res = func.EndInvoke(ar);
                Console.WriteLine(res);
            }, null);
            Console.ReadLine();
        }
        static void CallBack(IAsyncResult ar)
        {
            Func<int, string, int> f = ar.AsyncState as Func<int, string, int>;
            int res = f.EndInvoke(ar);
            Console.WriteLine(res);
        }
    }
}

image.png

2、通过thread类开启线程

2.1定义线程

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text11
{
    class Program
    {
        static void DownLoadFile()
        {
            Console.WriteLine("开始下载");
            Thread.Sleep(1000);
            Console.WriteLine("下载结束");
        }
        static void Main(string[] args)
        {
            Thread thread = new Thread(DownLoadFile);
            thread.Start();
            Console.WriteLine("Main");
            Console.ReadLine();
        }
    }
}

image.png

2.2如何传递参数

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text11
{
    class Program
    {
        static void DownLoadFile(object name)
        {
            Console.WriteLine("开始下载"+Thread.CurrentThread.ManagedThreadId+name);
            Thread.Sleep(1000);
            Console.WriteLine("下载结束");
        }
        static void Main(string[] args)
        {
            Thread thread = new Thread(DownLoadFile);
            thread.Start("***的种子");
            Console.WriteLine("Main");
            Console.ReadLine();
        }
    }
}

image.png
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text11
{
    class MyThread
    {
        public string FileName { get; set; }
        private string FilePath { get; set; }
        public MyThread(string Name, string Path)
        {
            this.FileName = Name;
            this.FilePath = Path;
        }
        public void DownLoadFile()
        {
            Console.WriteLine("开始下载" + FileName+"\n" +"文件地址:" +FilePath);
            Thread.Sleep(1000);
            Console.WriteLine("下载结束");
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text11
{
    class Program
    {
        ////方法一
        //static void DownLoadFile(object name)
        //{
        //    Console.WriteLine("开始下载"+Thread.CurrentThread.ManagedThreadId+name);
        //    Thread.Sleep(1000);
        //    Console.WriteLine("下载结束");
        //}
        //static void Main(string[] args)
        //{
        //    Thread thread = new Thread(DownLoadFile);
        //    thread.Start("***的种子");
        //    Console.WriteLine("Main");
        //    Console.ReadLine();
        //}

        //方法二
        static void Main(string[] args)
        {
            MyThread myThread = new MyThread("XXX.bt","http://www.XXX.dbs");
            Thread thread = new Thread(myThread.DownLoadFile);
            thread.Start();
            Console.ReadLine();
        }
    }
}

2.3前台线程和后台线程

线程有两种:前台线程和后台线程。区别是:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
.net环境使用Thread建立的线程默认情况下是前台线程,即线程属性IsBackground=false,在进程中,只要有一个前台线程未退出,进程就不会终止。主线程就是一个前台线程。而后台线程不管线程是否结束,只要所有的前台线程都退出(包括正常退出和异常退出)后,进程就会自动终止。
后台线程只需将sBackground = true即可

thread.IsBackground = true;

2.4线程优先级

2.5控制线程

调用线程控制方法.启动:Thread.Start();停止:Thread.Abort();暂停:Thread.Suspend();继续:Thread.Resume();
值得注意的是: 通过 Thread.Abort() 停下来的线程(或自行运行结束的线程),都无法直接通过 Thread.Start() 方法再次启动,必须重新创建一个线程启动。

3、线程池

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的[堆栈]大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在[托管代码]中空闲(如正在等待某个事件),则线程池将插入另一个[辅助线程]来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text11
{
    class Program
    {
        static void DownLoadFile(object name)
        {
            Console.WriteLine("开始下载" + Thread.CurrentThread.ManagedThreadId + name);
            Thread.Sleep(1000);
            Console.WriteLine("下载结束");
        }
        static void Main(string[] args)
        {
            ThreadPool.QueueUserWorkItem(DownLoadFile);
            ThreadPool.QueueUserWorkItem(DownLoadFile);
            ThreadPool.QueueUserWorkItem(DownLoadFile);
            ThreadPool.QueueUserWorkItem(DownLoadFile);
            ThreadPool.QueueUserWorkItem(DownLoadFile);
            ThreadPool.QueueUserWorkItem(DownLoadFile);
            ThreadPool.QueueUserWorkItem(DownLoadFile);
            Console.ReadLine();
        }
    }
}

image.png

注意:线程池中的线程都是后台线程,不能修改为前台线程,不能设置优先级

4、通过任务开启线程

4.1通过任务或任务工厂

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text11
{
    class Program
    {
        static void DownLoadFile()
        {
            Console.WriteLine("开始下载" );
            Thread.Sleep(1000);
            Console.WriteLine("下载结束");
        }
        static void DownLoadFile(object name)
        {
            Console.WriteLine("开始下载"+name );
            Thread.Sleep(1000);
            Console.WriteLine("下载结束");
        }
        static void Main(string[] args)
        {
            ////方法一:任务
            //Task task = new Task(DownLoadFile,"xxx");
            //task.Start();


            //方法二:任务工厂
            TaskFactory taskFactory = new TaskFactory();
            Task task = taskFactory.StartNew(DownLoadFile,"xxx");
            Console.WriteLine("Main");
            Console.ReadLine();
        }
    }
}

4.2连续任务

如果一个任务的执行依赖于另一个任务,即任务的执行有先后顺序。此时,我们可以使用连续任务。
task.ContinueWith(ReadNews)表示一个任务task结束后,才开始执行另一个任务。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text11
{
    class Program
    {
        static void DownLoadFile(object name)
        {
            Console.WriteLine("开始下载" + name);
            Thread.Sleep(1000);
            Console.WriteLine("下载结束");
        }
        static void ReadNews(Task obj)
        {
            Thread.Sleep(1000);
            Console.WriteLine("ReadNews");
        }
        static void Main(string[] args)
        {
            Task task = new Task(DownLoadFile, "xxx");
            Task task2 = task.ContinueWith(ReadNews);
            task.Start();
            Console.WriteLine("Main");
            Console.ReadLine();
        }
    }
}
image.png

4.3任务的层次结构

在一个任务中可以启动子任务,两个任务异步执行。默认情况下,子任务(即由外部任务创建的内部任务)将独立于其父任务执行。使用TaskCreationOptions.AttachedToParent显式指定将任务附加到任务层次结构中的某个父级。
如果父任务执行完了但是子任务没有执行完,则父任务的状态会被设置为WaitingForChildrenToComplete,只有子任务也执行完了,父任务的状态才会变成RunToCompletion。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text11
{
    class Program
    {
        //任务的层次结构
        static void DownLoad(object str)
        {
            Console.WriteLine("Parent Begin ID = " + Thread.CurrentThread.ManagedThreadId + " " + str);
            Task child = new Task(ChildWork,TaskCreationOptions.AttachedToParent);
            child.Start();
            Thread.Sleep(1000);
            Console.WriteLine("Parent 结束");
        }
        static void ChildWork()
        {
            Console.WriteLine("Child 开始");
            Thread.Sleep(5000);
            Console.WriteLine("Child 结束");
        }
        static void Main(string[] args)
        {
            Task task = new Task(DownLoad, "人民日报");
            task.Start();
            Thread.Sleep(2000);
            Console.WriteLine(task.Status);
            Thread.Sleep(4000);
            Console.WriteLine(task.Status);
            Console.WriteLine("Main");
            Console.ReadLine();
        }
    }
}

image.png

4.4任务的执行结果

使用Task的泛型版本,可以返回任务的执行结果。
下面例子中的TaskWithResult的输入为object类型,返回一个元组Tuple<int, int>。
定义调用TaskWithResult的任务时,使用泛型类Task<Tuple<int, int>>,泛型的参数定义了返回类型。通过构造函数,传递TaskWithResult,构造函数的第二个参数定义了TaskWithResult的输入值。
任务完成后,通过Result属性获取任务的结果。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Text11
{
    class Program
    {
        static void DownLoad(object str)
        {
        static Tuple<int, int> TaskWithResult(object obj)
        {
            Tuple<int, int> div = (Tuple<int, int>)obj;
            Thread.Sleep(1000);
            return Tuple.Create<int, int>(div.Item1 + div.Item2, div.Item1 - div.Item2);
        }
        static void Main(string[] args)
        {
            var task = new Task<Tuple<int, int>>(TaskWithResult, Tuple.Create<int, int>(8, 3));
            task.Start();
            Console.WriteLine(task.Result);
            task.Wait();
            Console.WriteLine("Result: {0} {1}", task.Result.Item1, task.Result.Item2);
            Console.ReadLine();
        }
        }
    }
}
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356