浅解多线程(二)之和尚们的那些事儿

本文链接

  1. 确定多线程的结束时间,thread的IsAlive属性
  2. 线程优先级,thread的ThreadPriority属性
  3. 线程通信之Monitor类
  4. 线程排队之Join
  5. 多线程互斥锁Mutex
  6. 信号量semaphore

确定多线程的结束时间,thread的IsAlive属性

在多个线程运行的背景下,了解线程什么时候结束,什么时候停止是很有必要的。

案例:老和尚念经计时,2本经书,2个和尚念,一人一本,不能撕破,最短时间念完,问老和尚们念完经书最短需要多长时间。

分析:首先在开始念经的时候给计时,记为A,最后在记下慢和尚念完经书时的时间,记为B。求B-A

代码:IsAlive属性:标识此线程已启动并且尚未正常终止或中止,则为 true,再念,没念完,努力中;否则为 false,念完啦,歇着。

 //和尚1,和尚2

        public Thread td1, td2;



        public void StarThread()

        {

            //开启一个线程执行Hello方法,即和尚1念菠萝菠萝蜜

            ThreadStart ts = new ThreadStart(Hello);

            td1 = new Thread(ts);

            td1.Start();

        }

        public void StarThread1()

        {

            //开启一个线程执行Welcome方法,即和尚2念大金刚经

            ThreadStart ts = new ThreadStart(Welcome);

            td2 = new Thread(ts);

            td2.Start();

        }

        public string sayh="", sayw="";



        //菠萝菠萝蜜

        public void Hello()

        {

            //

            sayh = "Hellow everyone ! ";

        }



        //大金刚经

        public  void Welcome()

        {   

            //

            sayw = "Welcome to ShangHai ! ";

            //偷懒10秒

            Thread.Sleep(10000);

        }



        protected void btn_StarThread_Click(object sender, EventArgs e)

        {

            //记时开始,预备念        

            Response.Write("开始念的时间: "+DateTime.Now.ToString() + "</br>");

            //和尚1就位

            StarThread();

            //和尚2就位

            StarThread1();



            int i = 0;

            while (i == 0)

            {

                //判断线程的IsAlive属性

                //IsAlive标识此线程已启动并且尚未正常终止或中止,则为 true;否则为 false。

                //如果两个都为false说明,线程结束终止

                if (!td1.IsAlive && !td2.IsAlive)

                {

                    i++;

                    if (i == 1)

                    {

                        //念得内容,绕梁三尺。

                        Response.Write("我们年的内容: "+(sayh + " + " + sayw) + "</br>");

                        Response.Write("念完时的时间: "+DateTime.Now.ToString());

                        Response.End();

                    }

                }

            }

        }

浅解多线程(二)之和尚们的那些事儿

线程优先级,thread的ThreadPriority属性

线程优先级区别于线程占有cpu时间的多少,当然优先级越高同等条件下占有的cpu时间越多。级别高的执行效率要高于级别低的。

优先级有5个级别:Lowest<BelowNormal<Normal<AboveNormal<Highest;默认为Normal。

案例:老和尚娶媳妇。佛祖说:你们3个和尚,清修刻苦,现特许你们娶媳妇啦,不过娶媳妇的只能是你们三个中间的一人。条件是我手中的经书谁能先念完,谁可以娶。

分析:和尚平时都很刻苦,各有特点,平时和尚1在lowest环境下念经,和尚2在normal环境下念经,和尚3在Highest环境下念经。

 protected void btn_StarThread_Click(object sender, EventArgs e)

        {

            Write();

        }



        //i为和尚1念的页数

        //j为和尚2念的页数

        //k为和尚3念的页数

        //c为经书总页数

        int i=0,j=0,k=0,c=10000000;



        //和尚1念经

        public void Jsi()

        {

            while (i <= c)

            {

                i+=1;

            }

        }

        //和尚2念经

        public void Jsj()

        {

            while (j <= c)

            {

                j+=1;

            }

        }

        //和尚3念经

        public void Jsk()

        {

            while (k <= c)

            {

                k+=1;

            }

        }

        public void Write()

        {

            //开启线程计算i

            ThreadStart sti = new ThreadStart(Jsi);

            Thread tdi = new Thread(sti);

            //设置线程优先级为Lowest。和尚1在Lowest环境下念经

            tdi.Priority = ThreadPriority.Lowest;



            //开启线程计算j

            ThreadStart stj = new ThreadStart(Jsj);

            Thread tdj = new Thread(stj);

            //设置线程优先级为Normal。和尚2在Normal环境下念经

            tdj.Priority = ThreadPriority.Normal;            



            //开启线程计算k

            ThreadStart stk = new ThreadStart(Jsk);

            Thread tdk = new Thread(stk);

            //设置线程优先级为Highest。和尚3在Highest环境下念经

            tdk.Priority = ThreadPriority.Highest;         

            

            //开始

            tdj.Start();

            tdk.Start();

            tdi.Start();

            int s = 0;

            while (s==0)

            {                

                if (k > c)

                {

                    s++;

                    Response.Write("比赛结束,结果如下:</br></br>");

                    Response.Write("和尚1在Lowest环境下念经:" + i + "页</br>和尚2在Normal环境下念经:" + j + "页</br>和尚3在Highest环境下念经:" + k + "页</br></br>");

                    Response.Write("佛祖又说:你念或者不念,苍老师,就在那里!");

                    Response.End();

                }

            }

        }

浅解多线程(二)之和尚们的那些事儿

为啦方便期间,从这以后,我要用控制台程序演示,操控线程。

线程通信之Monitor类

如果,你的线程A中运行锁内方法时候,需要去访问一个暂不可用资源B,可能在B上耗费很长的等待时间,那么这时候你的线程A,将占用锁内资源,阻塞其它线程访问锁定内容,造成性能损失。你该怎么解决这样子的问题呢?这样,让A暂时放弃锁,停留在锁中的,允许其它线程访问锁,而等B资源可用时,通知A让他继续锁内的操作。是不是解决啦问题,这样就用到啦这段中的Monitor类,提供的几个方法:Wait(),Pulse(),PulseAll(),这几个方法只能在当前锁定中使用。

Wait():暂时中断运行锁定中线程操作,释放锁,时刻等待着通知复活。

Pulse():通知等待该锁线程队列中的第一个线程,此锁可用。

PulseAll():通知所有锁,此锁可用。

案例:嵩山少林和尚开会。主持人和尚主持会议会不停的上舞台讲话,方丈会出来宣布大会开始,弟子们开始讨论峨眉山怎么走。

分析:主持人一个线程,方丈一个线程,弟子们一个线程,主持人贯彻全场。

 public class MutexSample

    {

        static void Main()

        {

            comm com = new comm();

            com.dhThreads();

            Console.ReadKey();

        }

    }

    public class comm

    {

        //状态值:0时主持人和尚说,1时方丈说,2时弟子们说,3结束。

        int sayFla;

        //主持人上台

        int i = 0;

        public void zcrSay()

        {

            lock (this)

            {

                string sayStr;

                if (i == 0)

                {

                    //让方丈说话

                    sayFla = 1;

                    sayStr = Thread.CurrentThread.Name+"今晚,阳光明媚,多云转晴,方丈大师,程祥云而来,传扬峨眉一隅,情况如何,还请方丈闪亮登场。";

                    Console.WriteLine(sayStr);

                    i++;

                    //此时sayFla=1通知等待的方丈线程运行

                    Monitor.Pulse(this);  

                    //暂时锁定主持人,暂停到这里,释放this让其它线程访问

                    Monitor.Wait(this);

                    

                }

                //被通知后,从上一个锁定开始运行到这里

                if (i == 1)

                {

                    //让弟子说话

                    sayFla = 2;

                    sayStr = Thread.CurrentThread.Name + "看方丈那幸福的表情,徜徉肆恣,愿走的跟他去吧。下面请弟子们各抒己见";

                    Console.WriteLine(sayStr);

                    i++;

                    //此时sayFla=12通知等待的弟子线程运行

                    Monitor.Pulse(this);  

                     //暂时锁定主持人,暂停到这里,释放this让其它线程访问

                    Monitor.Wait(this);                    

                }

                //被通知后,从上一个锁定开始运行到这里

                if (i == 2)

                {

                    sayFla = 3;

                    sayStr = Thread.CurrentThread.Name + "大会结束!方丈幸福!!苍老师你在哪里?!!放开那女孩 ...";

                    Console.WriteLine(sayStr);

                    i++;

                    Monitor.Wait(this); 

                }

            }

        }

        //方丈上台

        public void fzSay()

        {

            lock (this)

            {

                while (true)

                {

                    if (sayFla != 1)

                    {

                        Monitor.Wait(this);

                    }

                    if (sayFla == 1)

                    {

                        Console.WriteLine(Thread.CurrentThread.Name + "蓝蓝的天空,绿绿的湖水,我看见,咿呀呀呀,看见一老尼,咿呀呀,在水一方。愿意来的一起来,不愿来的苍老师给你们放寺里。。咿呀呀,我走啦。。。");

                        //交给主持人

                        sayFla = 0;

                        //通知主持人线程,this可用

                        Monitor.Pulse(this);

                    }

                }                

            }

        }

        //弟子上台

        public void dzSay()

        {

            lock (this)

            {

                while (true)

                {

                    if (sayFla != 2)

                    {

                        Monitor.Wait(this);  

                    }

                    if (sayFla == 2)

                    {

                        Console.WriteLine(Thread.CurrentThread.Name + "果真如此的话,还是方丈大师自己去吧!! 祝福啊  .... ");

                        //交给主持人

                        sayFla = 0;

                        Monitor.Pulse(this);

                    }

                }

                

            }

        } 

        public void dhThreads()

        {            

                Thread zcrTd = new Thread(new ThreadStart(zcrSay));

                Thread fzTd = new Thread(new ThreadStart(fzSay));

                Thread dzTd = new Thread(new ThreadStart(dzSay));

                zcrTd.Name = "主持人:";

                fzTd.Name = "方丈:";

                dzTd.Name = "弟子:";                

                zcrTd.Start();

                fzTd.Start();

                dzTd.Start();

        }

    }

浅解多线程(二)之和尚们的那些事儿

线程排队之Join

多线程,共享一个资源,先后操作资源。Join()方法,暂停当前线程,直到指定线程运行完毕,才唤醒当前线程。如果没有Join,多线程随机读取公用资源,没有先后次序。

案例:两个和尚念一本经书,老和尚年前半本书,小和尚念后半本书,小和尚调皮,非要先念,就给老和尚用迷魂药啦。。

分析:一本书6页,小和尚4-6,老和尚1-3,两个和尚,两个线程。

  public class 连接线程Join

    {

        //小和尚

        public static Thread litThread;

        //老和尚

        public static Thread oldThread;



        //老和尚念经

        static void oldRead()

        {

            //老和尚被小和尚下药

            litThread.Join();  //暂停oldThread线程,开始litThread,直到litThread线程结束,oldThread才继续运行,如果不适用Join将小和尚一句,老和尚一句,随即没有规则的。

            for (int i = 1; i <= 3; i++)

            {

                Console.WriteLine(i);

            }

        }

        //小和尚念经

        static void litRead()

        { 

            for (int i = 4; i <= 6; i++)

            {

                Console.WriteLine(i);

            }

        }

        static void Main(string[] args)

        {

            oldThread = new Thread(new ThreadStart(oldRead));

            litThread = new Thread(new ThreadStart(litRead));



            oldThread.Start();

            // FristThread.Join();   //暂停oldThread线程,开始litThread,直到litThread线程结束,oldThread才继续运行

            litThread.Start();

            Console.ReadKey();

        }

    }

浅解多线程(二)之和尚们的那些事儿

多线程互斥锁Mutex

 互斥锁是一个同步的互斥对象,适用于,一个共享资源,同时只能有一个线程能够使用。

共享资源加互斥锁,需要两部走:1.WaitOne(),他将处于等待状态知道可以获取资源上的互斥锁,获取到后,阻塞主线程运行,直到释放互斥锁结束。2.ReleaseMutex(),释放互斥锁,是其它线程可以获取该互斥锁。

案例:和尚写日记。最近寺庙香火不旺,为啦节约用水,方丈发话两个和尚用一个本子写日记。

分析:好比多个线程写日志,同时只能有一个线程写入日志文件。

 public class 多线程互斥锁Mutex

    {

        static void Main(string[] args)

        {

            IncThread ict = new IncThread("大和尚", 3);

            DecThread dct = new DecThread("小和尚", 3);

            Console.ReadKey();

        }

    }

    class SharedRes

    {

        public static int count = 0;

        //初始化互斥锁,没被获取

        public static Mutex mtx = new Mutex();

        ////初始化互斥锁,被主调线程获取

        //public static Mutex mtx = new Mutex(true);

    }



    class IncThread

    {

        int num;

        public Thread thrd;

        public IncThread(string name ,int n)

        {

            thrd = new Thread(new ThreadStart(this.run));

            thrd.Name = name;

            num = n;

            thrd.Start();

        }

        //写日记,过程

        void run()

        {

            Console.WriteLine(thrd.Name + " , 等待互斥锁 。");

            SharedRes.mtx.WaitOne();           

            Console.WriteLine(thrd.Name + " ,获得互斥锁 。");

            do

            {

                Thread.Sleep(500);

                SharedRes.count++;

                Console.WriteLine("今天我 " + thrd.Name + " 比较强,这样写吧 :" + SharedRes.count);

                num--;

            }while(num>0);

           Console.WriteLine(thrd.Name + " , 释放互斥锁 。");

           SharedRes.mtx.ReleaseMutex();

        }

    }

    class DecThread

    {

        int num;

        public Thread thrd;



        public DecThread(string name, int n)

        {

            thrd = new Thread(new ThreadStart(this.run));

            thrd.Name = name;

            num = n;

            thrd.Start();

        }

        //写日记,过程

        void run()

        {           

            Console.WriteLine(thrd.Name + ", 等待互斥锁 。");

            SharedRes.mtx.WaitOne();

            Console.WriteLine(thrd.Name + " ,获得互斥锁 。");

            do

            {

                Thread.Sleep(500);

                SharedRes.count--;

                Console.WriteLine("今天我 " + thrd.Name + " 比较衰,这样写吧 :" + SharedRes.count);

                num--;

            } while (num > 0);

            Console.WriteLine(thrd.Name + " , 释放互斥锁 。");

            SharedRes.mtx.ReleaseMutex();

        }

    }

浅解多线程(二)之和尚们的那些事儿

信号量semaphore

类似于互斥锁,只不过他可以指定多个线程来访问,共享资源。在初始化信号量的同时,指定多少个线程可以访问,假如允许2个线程访问,而却有3个线程等待访问,那么他将只允许2个访问,一旦已访问的2个线程中有一个访问完成释放信号量,那么没有访问的线程立马可以进入访问。

案例:和尚抓鸡,3个和尚抓鸡,只有两只鸡,那么鸡圈管理员只允许2个和尚先进,抓到说三句话放下,出来,让第三个和尚进去抓。

分析:三个线程,初始信号量允许2个线程访问。

   public class 信号量semaphore

    {

       static void Main(string[] args)

       {

           MyThread td1 = new MyThread("降龙");

           MyThread td2 = new MyThread("伏虎");

           MyThread td3 = new MyThread("如来");           

           td1.td.Start();

           td2.td.Start();

           td3.td.Start();

           Console.ReadKey();

       }    

    }



  public class MyThread

   {

       //初始化,新号量,允许2个线程访问,最大2也是2个。

       public static Semaphore sem = new Semaphore(2,2);

       public Thread td;

       public MyThread(string name)

       {

           td = new Thread(new ThreadStart(this.Run));

           td.Name = name;

       }

       //过程很美好

       public void Run()

       {

           Console.WriteLine(td.Name+",等待一个信号量。");

           sem.WaitOne();

           Console.WriteLine(td.Name+",已经获得新号量。");

           Thread.Sleep(500);
//很有深意的三句话
char[] cr = { 'a','o','e'}; foreach (char v in cr) { Console.WriteLine(td.Name+",输出v: "+v); Thread.Sleep(300); } Console.WriteLine(td.Name+",释放新号量。"); sem.Release(); } }

浅解多线程(二)之和尚们的那些事儿

 

 

结束,笑纳,海涵。

 

 

 

你可能感兴趣的:(多线程)