第四十二讲 深入线程-续 (并发线程测试及lock的使用)

来源:互联网 发布:java好用的分页插件 编辑:程序博客网 时间:2024/06/05 15:25
第四十二讲 深入线程-续

4. 后台线程
    1. 线程的IsBackground属性是用于将线程设置为后台线程
    2. .NET中共有两种类型的线程,一种是前台线程,一种是后台线程
    3. 它的区别在于,后台线程会随着主线程的结束而结束,而前台线程,应用程序要等待前台线程结束,应用程序才能结束。当给IsBackground属性赋值true时就指明了你建立的是后台线程,如果你建立时不指明类型,那么默认是前台线程。
    
5. 线程的优先级
    1. 当遇到多个线程抢资源的时候,操作系统要负责调度线程。如果想插队,则需要给线程指定优先级。
    2. 优先级相同的多个线程等待使用CPU,线程调度器就会使用一个循环调度规则,将CPU逐个交给线程使用。如果线程是被其他线程抢先了,它就会排在队列的最后。
    3. 在Thread类中,可以设置Priority属性,以影响线程的基本优先级。
    4. ThreadPriority枚举:
        1. Highest
        2. AboveeNormal
        3. BelowNormal
        4. Lowest
        
        
6. 并发问题
    不同的线程在相同的时间要求被执行。他们之间对资源就会产生并发。
    实践(冲突与有序)
    
    
7. 锁--lock:用lock语句锁定在线程中共享的变量,另一个线程就必须等待该 锁定的解除

    C#为同步访问变量提供了一个非常简单的方式,即使用C#语言的关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许线程进入执行,而其他线程必须等待。在C#中,关键字lock定义如下:
        lock(expression)
        {
            staement_block
        }
        
    1. expression代表你希望跟踪的对象,通常是对象引用。
    2. 如果你想保护一个类的实例,一般地,你可以使用THIS
    3. 如果你想保护一个静态变量(如互斥代码段在一个静态方法内部),一般使用类名就可以了
    4. 而staement_block就是互斥段的代码,这段代码在一时刻内只可能被一个线程执行。
    
    

8. 死锁:在死锁中,至少有两个线程被挂起,等待对方解除锁定。由于两个线程都在等待对方,就出现了死锁,线程将无限等待下去。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace Con422{    public class statuTest    {        int num = 5;        public void numTest(int i)        {            if (num == 5)            {                num++;                //下面这个追踪器里的两个参数里,第一次调用第一个参数,为真时继续向下执行                //第一次参数为假时,调用第二个参数,并提示消息框                System.Diagnostics.Trace.Assert(num == 6, "在当前"+Thread.CurrentThread.Name+"的第"+i + "次循环后发生并发问题!");            }            num = 5;        }    }    public class Test    {                public void TestStatu(object o)        {            statuTest s = o as statuTest;            int i = 0;            while (true)            {                i++;                //Thread.Sleep(1);//这个地方不能用阻塞,1个毫秒就会报错了                s.numTest(i);                //Console.WriteLine(Thread.CurrentThread.Name+"---"+i+"次");                //lock (s)//有锁了就好多了,但也要考虑到死锁的状况                //{                //    s.numTest(i);                //    Console.WriteLine(Thread.CurrentThread.Name);                //}            }        }    }    class Program    {        static Thread t;        static void Main(string[] args)        {            Console.WriteLine("\n****************并发线程测试及lock的使用******************\n");            statuTest s = new statuTest();            for (int i = 0; i < 20; i++)            {                Console.WriteLine("\n*******开始new第---{0}---个线程******\n",i);                //循环new线程出来,所有的线程去调用同一个对象                //new Thread(new Test().TestStatu).Start(s);                //使用lock锁                t = new Thread(new Test().TestStatu);                t.Name = i.ToString() + "号线程";                t.Start(s);            }        }    }}

补充前面写的实例:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace Con42{    class Program    {        static Thread newThread;        static void Main(string[] args)        {            Console.WriteLine("我是主线程,开始执行");            //测试结果是,如果新线程为前台线程,当主线程结束时,需要等待新线程结束才退出            //如果新线程为后台线程,那么新线程会随着主线程的结束而结束            newThread = new Thread(newthread);            newThread.Name = "新线程";//定义新线程的名字            newThread.IsBackground = false;//非后台线程            newThread.Start();            Console.WriteLine("主线程到这里结束了");            Thread.Sleep(1000);            Console.WriteLine("\n****************线程优先级测试******************\n");            //优先级一共有:            //ThreadPriority枚举:    //1. Highest            //2. AboveeNormal            //3. BelowNormal            //4. Lowest            //new几个线程,分别赋于不同的优先级,默认为Normal            priorityTest pt=new priorityTest();            Thread t01 = new Thread(pt.Function);            t01.Name = "一般优先级线程t01";            t01.Priority = ThreadPriority.Normal;//这个一句可有可无,因为它是默认值                        Thread t02 = new Thread(pt.Function);            t02.Name = "一般以上优先级线程t02";            t02.Priority = ThreadPriority.AboveNormal;                        Thread t03 = new Thread(pt.Function);            t03.Name = "一般以下优先级线程t03";            t03.Priority = ThreadPriority.BelowNormal;                        Thread t04 = new Thread(pt.Function);            t04.Name = "最低优先级线程t04";            t04.Priority = ThreadPriority.Lowest;                        Thread t05 = new Thread(pt.Function);            t05.Name = "最高优先级t05";            t05.Priority = ThreadPriority.Highest;            //结果不如意            //t01.Start(t01);//一般优先级            //t02.Start(t02);//一般以上            //t03.Start(t03);//一般以下            //t04.Start(t04);//最低            //t05.Start(t05);//最高            ////结果不如意,好似跟先后执行的顺序也有关            //t01.Start();//一般优先级            //t02.Start();//一般以上            //t03.Start();//一般以下            //t04.Start();//最低            //t05.Start();//最高            //结果不如意            //t05.Start(t05);//最高            //t02.Start(t02);//一般以上            //t01.Start(t01);//一般优先级            //t03.Start(t03);//一般以下            //t04.Start(t04);//最低            //下面这种方式好些            t05.Start();//最高            t02.Start();//一般以上            t01.Start();//一般优先级            t03.Start();//一般以下            t04.Start();//最低                        //测试5秒后,别忘记把开关关上,刚忘关了,CPU四核满载了            Thread.Sleep(3000);//阻塞主线程5秒钟给线程优先级测试            pt.Statu = false;            //结果不如人意,CPU并没有按我设置的优先线得出让人满意的结果            Thread.Sleep(1000);            Console.WriteLine("\n****************并发线程测试******************\n");            //定义一个线程数组            Thread[] arrayThread = new Thread[10];            //遍历每个线程并实例化,设置线程名            for (int i = 0; i < 10; i++)            {                arrayThread[i] = new Thread(BingFaTest);                arrayThread[i].Name = "线程" + i;            }            //遍历执行每个线程            foreach (Thread t in arrayThread)            {                t.Start();                //如果这个地方加阻塞呢,果然好一些                //Thread.Sleep(100);            }            Console.ReadKey();        }        public static void newthread()        {            Console.WriteLine("我是{0},开始执行",newThread.Name);            //Thread.Sleep(3000);//新线程休息2秒钟            Console.WriteLine("{0}也结束了",newThread.Name);        }        public static void BingFaTest()        {            Console.WriteLine("\n---------{0}正在打印数字--------\n",Thread.CurrentThread.Name);            for (int i = 0; i < 10; i++)            {                Console.Write("{0}({1})",i,Thread.CurrentThread.Name);            }            //如果不加这个阻塞,那每个线程会正常运行            //启用这个阻塞,部分打印就会有点小乱了            //Thread.Sleep(500);//稍有阻塞就乱            Random r = new Random();            Thread.Sleep(r.Next());//还是一样稍有阻塞就乱        }    }    /// <summary>    /// 线程优先级测试类    /// </summary>    public class priorityTest    {        bool statu;        public bool Statu        {            set { statu = value; }        }        public priorityTest()        {            this.statu = true;        }        public void Function(object o)        {            //Thread t = o as Thread;            long count=0L;//计数器            while (this.statu)            {                count++;            }            //Console.WriteLine("{0},优先级:{1},计数: {2}",t.Name,t.Priority,count.ToString());            Console.WriteLine("{0},优先级:{1},计数: {2}", Thread.CurrentThread.Name, Thread.CurrentThread.Priority, count.ToString());        }    }}


0 0
原创粉丝点击