zoukankan      html  css  js  c++  java
  • 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();//释放信号量
            }
  • 相关阅读:
    c++中重载、重写、覆盖的区别
    c++值传递,指针传递,引用传递以及指针与引用的区别
    c/c++中static与extern关键字介绍
    Typedef和#define之间的区别
    c++中sizeof()的用法介绍
    c++笔试题:不使用第三个变量来交换俩个变量的数值
    c++位运算符介绍
    3.高并发教程-基础篇-之分布式全文搜索引擎elasticsearch的搭建
    2.高并发教程-基础篇-之nginx+mysql实现负载均衡和读写分离
    1.高并发教程-基础篇-之nginx负载均衡的搭建
  • 原文地址:https://www.cnblogs.com/lgxlsm/p/5092418.html
Copyright © 2011-2022 走看看