C#多线程

1.使用多线程的几种方式

    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 30; i++)
            {
                //ThreadStart是一个委托,这个委托的定义为void ThreadStart(),没有参数与返回值。
                ThreadStart threadStart = new ThreadStart(Calculate);
                Thread thread = new Thread(threadStart);
                thread.Start();
            }
            Thread.Sleep(2000);
            Console.Read();
        }
        public static void Calculate()
        {
            DateTime time = DateTime.Now;//得到当前时间
            Random ra = new Random();//随机数对象
            Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间
            Console.WriteLine(time.Minute + ":" + time.Millisecond);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 30; i++)
            {
                //ParameterThreadStart委托定义为void ParameterizedThreadStart(object state),有一个参数但是没有返回值。
                ParameterizedThreadStart tStart = new ParameterizedThreadStart(Calculate);
                Thread thread = new Thread(tStart);
                thread.Start(i);//传递参数
            }
            Thread.Sleep(2000);
            Console.Read();
        }
        public static void Calculate(object arg)
        {
            Random ra = new Random();//随机数对象
            Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间
            Console.WriteLine(arg);
        }
    }
  class Program
    {
        static void Main(string[] args)
        {
            //使用线程类可以有多个参数与多个返回值,十分灵活!
            MyThread mt = new MyThread(100);
            ThreadStart threadStart = new ThreadStart(mt.Calculate);
            Thread thread = new Thread(threadStart);
            thread.Start();
            //等待线程结束
            while (thread.ThreadState != ThreadState.Stopped)
            {
                Thread.Sleep(10);
            }
            Console.WriteLine(mt.Result);//打印返回值
            Console.Read();
        }
    }

    public class MyThread//线程类
    {
        public int Parame { set; get; }//参数
        public int Result { set; get; }//返回值
        //构造函数
        public MyThread(int parame)
        {
            this.Parame = parame;
        }
        //线程执行方法
        public void Calculate()
        {
            Random ra = new Random();//随机数对象
            Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间
            Console.WriteLine(this.Parame);
            this.Result = this.Parame * ra.Next(10, 100);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            int Parame = 100;//当做参数
            int Result = 0;//当做返回值
            //使用匿名方法启动线程可以有多个参数和返回值,而且使用非常方便!
            ThreadStart threadStart = new ThreadStart(delegate()
            {
                Random ra = new Random();//随机数对象
                Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间
                Console.WriteLine(Parame);//输出参数
                Result = Parame * ra.Next(10, 100);//计算返回值
            });

            Thread thread = new Thread(threadStart);
            thread.Start();//多线程启动匿名方法
            //等待线程结束
            while (thread.ThreadState != ThreadState.Stopped)
            {
                Thread.Sleep(10);
            }
            Console.WriteLine(Result);//打印返回值
            Console.Read();
        }
    }

2.使用委托开启多线程(多线程深入)

    //1、用委托(Delegate)的BeginInvoke和EndInvoke方法操作线程
    //BeginInvoke方法可以使用线程异步地执行委托所指向的方法。
    //然后通过EndInvoke方法获得方法的返回值(EndInvoke方法的返回值就是被调用方法的返回值)
    //,或是确定方法已经被成功调用。
    class Program
    {
        private delegate int NewTaskDelegate(int ms);
        private static int newTask(int ms)
        {
            Console.WriteLine("任务开始");
            Thread.Sleep(ms);
            Random random = new Random();
            int n = random.Next(10000);
            Console.WriteLine("任务完成");
            return n;
        }
        static void Main(string[] args)
        {
            NewTaskDelegate task = newTask;
            IAsyncResult asyncResult = task.BeginInvoke(2000, null, null);
            //EndInvoke方法将被阻塞2秒
            int result = task.EndInvoke(asyncResult);
            Console.WriteLine(result);
            Console.Read();
        }
    }
    //使用IAsyncResult.IsCompleted属性来判断异步调用是否完成
    class Program
    {
        private delegate int NewTaskDelegate(int ms);
        private static int newTask(int ms)
        {
            Console.WriteLine("任务开始");
            Thread.Sleep(ms);
            Random random = new Random();
            int n = random.Next(10000);
            Console.WriteLine("任务完成");
            return n;
        }
        static void Main(string[] args)
        {
            NewTaskDelegate task = newTask;
            IAsyncResult asyncResult = task.BeginInvoke(2000, null, null);
            //等待异步执行完成
            while (!asyncResult.IsCompleted)
            {
                Console.Write("*");
                Thread.Sleep(100);
            }
            // 由于异步调用已经完成,因此, EndInvoke会立刻返回结果
            int result = task.EndInvoke(asyncResult);
            Console.WriteLine(result);
            Console.Read();
        }
    }
    //3、使用WaitOne方法等待异步方法执行完成
    //WaitOne的第一个参数表示要等待的毫秒数,在指定时间之内,WaitOne方法将一直等待,
    //直到异步调用完成,并发出通知,WaitOne方法才返回true。当等待指定时间之后,
    //异步调用仍未完成,WaitOne方法返回false,如果指定时间为0,
    //表示不等待,如果为-1,表示永远等待,直到异步调用完成。
    class Program
    {
        private delegate int NewTaskDelegate(int ms);
        private static int newTask(int ms)
        {
            Console.WriteLine("任务开始");
            Thread.Sleep(ms);
            Random random = new Random();
            int n = random.Next(10000);
            Console.WriteLine("任务完成");
            return n;
        }
        static void Main(string[] args)
        {
            NewTaskDelegate task = newTask;
            IAsyncResult asyncResult = task.BeginInvoke(2000, null, null);
            //等待异步执行完成
            while (!asyncResult.AsyncWaitHandle.WaitOne(100, false))
            {
                Console.Write("*");
            }
            int result = task.EndInvoke(asyncResult);
            Console.WriteLine(result);
            Console.Read();
        }
    }
    //4、使用回调方式返回结果
    //要注意的是“my.BeginInvoke(3,300, MethodCompleted, my)”,BeginInvoke方法的参数传递方式:前面一部分(3,300)是其委托本身的参数。
    //倒数第二个参数(MethodCompleted)是回调方法委托类型,他是回调方法的委托,此委托没有返回值,有一个IAsyncResult类型的参数,
    //当method方法执行完后,系统会自动调用MethodCompleted方法。
    //最后一个参数(my)需要向MethodCompleted方法中传递一些值,一般可以传递被调用方法的委托,这个值可以使用IAsyncResult.AsyncState属性获得。
    class Program
    {
        private delegate int MyMethod(int second, int millisecond);
        //线程执行方法
        private static int method(int second, int millisecond)
        {
            Console.WriteLine("线程休眠" + (second * 1000 + millisecond) + "毫秒");
            Thread.Sleep(second * 1000 + millisecond);
            Random random = new Random();
            return random.Next(10000);
        }
        //回调方法
        private static void MethodCompleted(IAsyncResult asyncResult)
        {
            if (asyncResult == null || asyncResult.AsyncState == null)
            {
                Console.WriteLine("回调失败!!!");
                return;
            }
            int result = (asyncResult.AsyncState as MyMethod).EndInvoke(asyncResult);
            Console.WriteLine("任务完成,结果:" + result);
        }
        static void Main(string[] args)
        {
            MyMethod my = method;
            IAsyncResult asyncResult = my.BeginInvoke(3, 300, MethodCompleted, my);
            Console.WriteLine("任务开始");
            Console.Read();
        }
    }
    //5、其他组件的BeginXXX和EndXXX方法
    //在其他的.net组件中也有类似BeginInvoke和EndInvoke的方法,如System.Net.HttpWebRequest类的BeginGetResponse和EndGetResponse方法。
    //其使用方法类似于委托类型的BeginInvoke和EndInvoke方法,例如:
    class Program
    {
        //回调函数
        private static void requestCompleted(IAsyncResult asyncResult)
        {
            if (asyncResult == null || asyncResult.AsyncState == null)
            {
                Console.WriteLine("回调失败");
                return;
            }
            HttpWebRequest hwr = asyncResult.AsyncState as HttpWebRequest;
            HttpWebResponse response = (HttpWebResponse)hwr.EndGetResponse(asyncResult);
            StreamReader sr = new StreamReader(response.GetResponseStream());
            string str = sr.ReadToEnd();
            Console.WriteLine("返回流长度:" + str.Length);
        }

        static void Main(string[] args)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.baidu.com");
            //异步请求
            IAsyncResult asyncResult = request.BeginGetResponse(requestCompleted, request);
            Console.WriteLine("任务开始");
            Console.Read();
        }
    }

 3.多线程访问GUI界面的处理

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //使用该方式不会有无响应的情况发生,强烈建议使用该方式。
        //此方式不会发生界面无响应的关键点:调用this.textBox1.Invoke(action)
        //就是在拥有this.textBox1对象的线程(不一定是当前线程,多数是主线程)上调用action委托,
        //若action委托指向的方法执行时间过长就会使得界面无响应!而该方式中action委托指向的方法执行时间极为短。
        private void button1_Click(object sender, EventArgs e)
        {
            Thread thread = new Thread(Flush);
       //当初始化一个线程,把Thread.IsBackground=true的时候,指示该线程为后台线程。后台线程将会随着主线程的退出而退出。 thread.IsBackground
= true; thread.Start(); } //线程执行的方法 private void Flush() { //定义委托 Action action = delegate() { this.textBox1.AppendText("不在当前" + DateTime.Now.ToString() + " "); }; while (true) { //判断能否到当前线程操作该组件 if (this.textBox1.InvokeRequired) { //不在当前线程上操作 this.textBox1.Invoke(action);//调用委托 } else { //在当前线程上操作 this.textBox1.AppendText("在当前" + DateTime.Now.ToString() + " "); } Thread.Sleep(1000); } } private void button2_Click(object sender, EventArgs e) { this.textBox1.AppendText("Btn2点击了" + DateTime.Now.ToString() + " "); } //使用这种方法时,这个btn会被锁定,其他的btn点击无效 private void button3_Click(object sender, EventArgs e) { while (true) { this.textBox1.AppendText("在当前" + DateTime.Now.ToString() + " "); Thread.Sleep(1000); } } }
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            //指示是否能报告进度。要执行 ReportProgress 方法,需要先设置该属性为 true。
            backgroundWorker1.WorkerReportsProgress = true;
            //DoWork—当执行BackgroundWorker.RunWorkerAsync方法时会触发该事件,并且传递DoWorkEventArgs参数
            backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
            //操作处理中获得的处理状态变化,通过BackgroundWorker.ReportProgress方法触发该事件
            backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
            //异步操作完成或中途终止会触发该事件。如果需要提前终止执行后台操作,可以调用
            backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.backgroundWorker1.RunWorkerAsync();//开始执行后台操作。引发 DoWork 事件
        }

        //处理事务事件
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //初始化进度条
            this.progressBar1.Maximum = 100;
            this.progressBar1.Minimum = 0;
            //模拟事物处理
            for (int i = 0; i < 100; i++)
            {
                Thread.Sleep(10);
                //局部操作完成事件触发
                this.backgroundWorker1.ReportProgress(i, null);
            }
        }
        //局部操作完成时执行的方法
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.progressBar1.Value = e.ProgressPercentage;//设置进度条值
        }
        //事物处理完成时触发
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            MessageBox.Show(null, "工作线程完成!", "提示");
        }
    }
    //许多时候,我们需要用多线程,但是又不希望线程的数量过多,这就是线程池的作用,.Net为我们提供了现成的线程池ThreadPool。
    //每一个进程都有一个线程池,线程池的默认大小是25,我们可以通过SetMaxThreads方法来设置其最大值。
    //注意:因为WaitCallback委托的原型是void WaitCallback(object state),那没有办法,我们只能将多个参数封装到一个Object中。
    class Program
    {
        //线程方法
        public static void ThreadProc(object i)
        {
            Console.WriteLine(i.ToString());
            Thread.Sleep(1000);
        }
        public static void Main()
        {
            ThreadPool.SetMaxThreads(3, 3);//设置线程池
            for (int i = 0; i < 20; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), "线程" + i);
            }
            //Console.WriteLine("运行结束");
            Console.Read();
        }
    }

5.线程同步

//(1)代码块同步(Monitor与lock)
    //使用Monitor类的使用与lock关键字的使用在实现原理上相同。
    //Monitor.Enter 方法:   在指定对象上获取排他锁。
    //Monitor.TryEnter 方法:试图获取指定对象的排他锁。
    //Monitor.Exit 方法:    释放指定对象上的排他锁。
    //Monitor.Wait 方法:    释放对象上的锁并阻塞当前线程,直到它重新获取该锁。
    //Monitor.Pulse 方法:   通知等待队列中的线程锁定对象状态的更改。
    //Monitor.PulseAll 方法:通知所有的等待线程对象状态的更改。
    class Program
    {
        private int Count = 0;
        //线程执行方法
        public void ThreadProc()
        {
            //Monitor.Enter(this);
            //Thread.Sleep(200);
            //Count++;
            //Console.WriteLine(Count);
            //Monitor.Exit(this);
            //等同于
            lock (this)
            {
                Thread.Sleep(200);
                Count++;
                Console.WriteLine(Count);
            }
        }
        public static void Main()
        {
            Program p = new Program();
            for (int i = 0; i < 100; i++)
            {
                Thread t = new Thread(p.ThreadProc);
                t.Start();
            }
            Console.Read();
        }
    }
    //使用WaitAll静态方法
    //理解AutoResetEvent.WaitAll(Waits)静态方法:WaitAll静态方法就是阻塞当前线程,直到Waits数组里的所有元素都调用Set()方法发送信号,再继续执行当前线程。
    class Program
    {
        public static void Main()
        {
            AutoResetEvent[] Waits = new AutoResetEvent[10];
            for (int i = 0; i < 10; i++)
            {
                int temp = i;
                Waits[temp] = new AutoResetEvent(false);
                Action thread = delegate()
                {
                    //线程执行方法
                    Console.WriteLine("线程:" + temp);
                    Thread.Sleep(1000);
                    Waits[temp].Set();//发送线程执行完毕信号
                };
                ThreadStart ts = new ThreadStart(thread);
                Thread t = new Thread(ts);
                t.Start();
            }
            AutoResetEvent.WaitAll(Waits);//等待Waits中的所有对象发出信号
            Console.WriteLine("线程全部执行完毕!");
            Console.Read();
        }
    }
//使用WaitAny静态方法
    //理解AutoResetEvent.WaitAny(Waits)静态方法:WaitAny静态方法就是阻塞当前线程,只要Waits数组有一个元素调用Set()方法发送信号,就继续执行当前线程。
    class Program
    {
        public static void Main()
        {
            AutoResetEvent[] Waits = new AutoResetEvent[10];
            for (int i = 0; i < 10; i++)
            {
                Waits[i] = new AutoResetEvent(false);//初始化Waits
            }
            for (int i = 0; i < 10; i++)
            {
                int temp = i;
                Action thread = delegate()
                {
                    if (temp > 0)
                    {
                        AutoResetEvent.WaitAny(Waits);//等待上一个线程执行完毕
                    }
                    //线程执行方法
                    Thread.Sleep(1000);
                    Waits[temp].Set();//发送线程执行完毕信号
                    Console.WriteLine("线程:" + temp + "执行完毕");
                };
                ThreadStart ts = new ThreadStart(thread);
                Thread t = new Thread(ts);
                t.Start();
            }
            Console.Read();
        }
    //使用WaitOne成员方法
    //理解Wait.WaitOne()成员方法:WaitOne方法就是阻塞当前线程,只要Wait对象调用了Set()方法发送信号,就继续执行当前线程。
    class Program
    {
        public static void Main()
        {
            AutoResetEvent Wait = new AutoResetEvent(false);
            for (int i = 0; i < 10; i++)
            {
                Action thread = delegate()
                {
                    //线程执行方法
                    Thread.Sleep(1000);
                    Wait.Set();//发送线程执行完毕信号
                    Console.WriteLine("线程:" + i + "执行完毕");
                };
                ThreadStart ts = new ThreadStart(thread);
                Thread t = new Thread(ts);
                t.Start();
                Wait.WaitOne();//等待调用 Waits.Set()
            }
            Console.Read();
        }
    }
    class Program
    {
        private static ManualResetEvent Wait = new ManualResetEvent(false);
        public static void Main()
        {
            Wait.Set();//设置线程状态为允许执行
            Thread thread1 = new Thread(Method);
            thread1.Start("线程1");
            Thread.Sleep(1000);//等待线程1执行
            Wait.Reset();//必须手动复位线程状态,使状态为不允许执行
            Thread thread2 = new Thread(Method);
            thread2.Start("线程2");//线程2将会一直等待信号
            Console.WriteLine("主线程结束");
            Console.Read();
        }
        //线程执行方法
        private static void Method(Object o)
        {
            Wait.WaitOne();//等待信号
            Console.WriteLine(o.ToString());
        }
    }
    //Interlocked类为多个线程共享的变量提供原子操作。
    //原子操作:Interlocked.Increment()操作是一个原子操作,作用是:Count++ 。
    //原子操作,就是不能被更高等级中断抢夺优先的操作。由于操作系统大部分时间处于开中断状态,
    //所以,一个程序在执行的时候可能被优先级更高的线程中断。而有些操作是不能被中断的,
    //不然会出现无法还原的后果,这时候,这些操作就需要原子操作。就是不能被中断的操作。
    class Program
    {
        private static int Count = 0;
        static void Main(string[] args)
        {
            for (int i = 0; i < 100; i++)
            {
                Thread thread = new Thread(Method);
                thread.Start("线程" + i);
            }
            Thread.Sleep(1000 * 3);//休眠足够的时间等待所有线程执行完毕
            Console.WriteLine("操作后的结果:" + Program.Count);
            Console.ReadLine();
        }
        //线程执行方法
        private static void Method(Object o)
        {
            Thread.Sleep(500);
            //原子操作,类似:Program.Count++
            Interlocked.Increment(ref Program.Count);
            //Program.Count++;//非原子操作
            Console.WriteLine(o.ToString());
        }
    }
    //使用Monitor或Mutex进行同步控制的问题:由于独占访问模型不允许任何形式的并发访问,这样的效率总是不太高。
    //许多时候,应用程序在访问资源时是进行读操作,写操作相对较少。为解决这一问题,C#提供了System.Threading.ReaderWriterLock类以适应多用户读/单用户写的场景。
    //该类可实现以下功能:如果资源未被写操作锁定,那么任何线程都可对该资源进行读操作锁定,并且对读操作锁数量没有限制,即多个线程可同时对该资源进行读操作锁定,
    //以读取数据。如果资源未被添加任何读或写操作锁,那么一个且仅有一个线程可对该资源添加写操作锁定,以写入数据。简单的讲就是:读操作锁是共享锁,
    //允许多个线程同时读取数据;写操作锁是独占锁,同一时刻,仅允许一个线程进行写操作。
    //ReaderWriterLock类:定义支持单个写线程和多个读线程的锁。
    //ReaderWriterLockSlim类:表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问。
    class Program
    {
        private static int Count = 0;//资源
        static ReaderWriterLock rwl = new ReaderWriterLock();//读、写操作锁
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                Thread thread = new Thread(Read);//读线程
                thread.Start("线程" + i);
            }
            for (int i = 0; i < 10; i++)
            {
                Thread thread = new Thread(Write);//写线程
                thread.Start("--线程" + i);
            }
            Console.ReadKey();
        }
        private static void Read(Object o)//读数据
        {
            rwl.AcquireReaderLock(1000 * 20); //申请读操作锁,在20s内未获取读操作锁,则放弃
            Console.WriteLine(o.ToString() + "读取数据:" + Program.Count);
            Thread.Sleep(500);
            rwl.ReleaseReaderLock();//释放读操作锁
        }
        private static void Write(Object o)//写数据
        {
            rwl.AcquireWriterLock(1000 * 20);//申请写操作锁,在20s内未获取写操作锁,则放弃
            Thread.Sleep(500);
            Console.WriteLine(o.ToString() + "写数据:" + (++Program.Count));
            rwl.ReleaseWriterLock();//释放写操作锁
        }
    }
        private static Semaphore semaphore = new Semaphore(0, 5);//初始化信号量
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                Thread thread = new Thread(Method);
                thread.Start("线程" + i);
            }
            semaphore.Release(2);//释放信号量2个
            Console.WriteLine("主线程运行完毕!");
            Console.Read();
        }
        //线程执行方法
        private static void Method(object o)
        {
            semaphore.WaitOne();//等待信号量
            Thread.Sleep(1000);
            Console.WriteLine(o.ToString());
            semaphore.Release();//释放信号量
        }
原文地址:https://www.cnblogs.com/lgxlsm/p/5092418.html