zoukankan      html  css  js  c++  java
  • 线程的学习与使用

    1. 一、线程的简单创建

     可以把要执行的方法当做参数传递给线程,还有一种就是通过Lambda表达式匿名函数去直接创建。

    static void Test()
    
    {
    
    ///直接把方法传递给线程
    
    Thread thread = new Thread(Test);
    
    thread.Start();
    
     
    
    ///匿名函数创建线程
    
    Thread th2 = new Thread(() =>
    
    {
    
    Console.WriteLine("匿名创建");
    
    });
    
    th2.Start();
    
    Console.ReadKey();
    
    Console.WriteLine("方法");
    
     
    
    }
    

      

    1. 线程的一些简单操作

      nterrupt()。这个方法作用是唤醒沉睡的线程。当线程沉睡的时候,调用Interrupt()方法,这会把当前沉睡的线程唤醒,并抛出ThreadInterruptedException

       

     //唤醒线程
    Thread thread = new Thread(() =>
    {
    Console.WriteLine("线程开始啦");
    Console.WriteLine("睡着啦");
    try
    {
    Thread.Sleep(50000);
    }
    catch (ThreadInterruptedException ex)
    {
    Console.WriteLine("被叫醒啦");
    }
    Console.WriteLine("醒啦");
    });
    thread.Start();
    Console.WriteLine("按任意键唤醒线程");
    Console.ReadKey();
    thread.Interrupt();
    Console.ReadKey();

     

       

     

    三、线程的一些小细节

        Thread.Sleep();//休眠线程,即让当前的线程休眠指定的时间。

        Thread.Abort ();//终止线程,即抛出一个ThreadAbortException

        线程的参数化:

        当执行下面的语句我们想要输出的值为5但实际输出的却为6,因为在线程还未执行完成的时候又重新给i赋值为6,所以当线程执行的时候输出i的值就为6了。若想让线程输出指定的值的话,就得为该线程传递参数进去,给线程指定

    默认的参数。

     

     线程创建的时候默认的为非后台线程。当所有的非后台线程全部执行完后,进程才会关闭,否则看起来主线程关闭了,但是该进程却并没有关闭,依旧在后台运行着等待着其余非后台线程的执行。

    把线程设置为后台线程就不会出现上述的情况了,把线程设置为"后台线程"后,所有"非后台线程"执行结束后程序就会退出,不会去等后台程序是否执行完。设置后台线程:thread.IsBackground

    线程的优先级:

        thread.Priority = ThreadPriority.Normal;//线程创建时的默认级别

        thread.Priority = ThreadPriority.Highest;//最高优先级

        thread.Priority = ThreadPriority.Lowest;//最低优先级

        thread.Priority = ThreadPriority.BelowNormal;//Normal之后Lowest之前

        thread.Priority = ThreadPriority.AboveNormal;//Highest之后在Normal

    四、线程同步

        下面程序按理来说输出的值应该为10000才对,但是输出的却不是10000.原因很简单就是因为当thread线程在操作count的时候,thread2也在操作count。当threadcount赋值之后,thread2重新再为count赋值就把count的值重新又给初始化

    了,所以count的值输出的就不为10000

               线程同步就是解决多个线程同时操作一个资源的问题。下面代码就是简单的实现线程同步。使用lock去解决多线程的问题,lock C#中的关键字,他要锁定一个资源,lock 的特点是:同时只能有一个线程进入 lock 的对象的范围,

    其他 lock 的线程就要等。就是多个线程同一时候只能有一个线程去执行被标记锁的对象。

    int count = 0;
    
    Thread thread = new Thread(() =>
    
    {
    
    lock (Lock)//添加锁 设置线程锁的对象同一时间只能有一个线程去操作它
    
    {
    
    for (int i = 0; i < 5000; i++)
    
    {
    
    count++;
    
    Thread.Sleep(1);
    
    }
    
    }
    
    });
    
     
    
    Thread thread2 = new Thread(() =>
    
    {
    
    lock (Lock)//添加锁
    
    {
    
    for (int j = 0; j < 5000; j++)
    
    {
    
    count++;
    
    Thread.Sleep(1);
    
     
    
    }
    
    }
    
    });
    
    thread2.Start();
    
    thread.Start();
    
    while (thread.IsAlive) { }
    
    while (thread2.IsAlive) { }//等待线程结束
    
    Console.WriteLine(count);

    五、Monitor

    lock关键字相当于对Monitor的调用。Monitor类的作用就是把一个对象给锁起来,若有线程在用的话就等待对方释放解锁,然后自己用的时候再把这个对象给锁起来。Monitor的三个最常用的方法就是。

    Monitor.Enter();//为指定对象加上锁

    Monitor.Exit(Lock);//释放锁,释放对象,解锁。

    Monitor.TryEnter();这个方法放回的是一个bool类型,若指定的对象被锁定之后,它不会去等待释放,而是返回false。下面就是对Monitor的简单应用。

       
     public static Object Lock = new object();//设置线程锁的对象同一时间只能有一个线程去操作它
            static void Main(string[] args)
            {
                int count = 0;
                Thread thread = new Thread(
                    () =>
                    {
                        for (int i = 0; i < 100; i++)
                        {
                            try
                            {
                                Monitor.Enter(Lock);//加上锁
                                count++;
                                Console.WriteLine("开始借钱");
                                Thread.Sleep(1000);
                                Console.WriteLine("借了" + count);
    
                        
                            }
                            finally
                            {
                                Monitor.Exit(Lock);//释放锁 
                            }
                        }
    
                        
                    }
                    );
                Thread thread2 = new Thread(
                    () =>
                    {
    
                        
    
                        for (int j = 0; j < 100; j++)
                        {
                            try
                            {
                                Monitor.Enter(Lock);//加上锁
                                count++;
                                Console.WriteLine(DateTime.Now.ToString() + "--开始还钱");
                                Thread.Sleep(1000);
                                Console.WriteLine(DateTime.Now.ToString() + "还了" + count);                          
                            }
                            finally
                            {
                                Monitor.Exit(Lock);//释放锁 
                            }
    
                        }
    
                    }
                    );
                thread.Start();
                thread2.Start();
                thread.Join();
                thread2.Join();
            }
     

    六、单例模式练习

    1、饿汉模式

    public class GetOne
    
    {
    //单例模式之饿汉模式
    private static GetOne test = new GetOne();
    private GetOne()//构造函数私有化
    {
    
    }
    public static GetOne GetOnly()
    {
    return test;
    }
    
    }

    2、懒汉模式加上线程的同步

    public class GetOne
        {
            private static Object Lock = new object();//创建锁对象
            //单例模式之懒汉式
            private static GetOne test = null;
            private GetOne()//构造函数私有化
            {
    
            }
            public static GetOne GetOnly()
            {
                if (test == null)//判断GetOne是否为null。多加上这个判断是为了减少上锁的次数
                {
                    lock (Lock)//若为null就加上锁去创建,防止多个线程同时创建
                    {
                        if (test == null)
                        {
                            test = new GetOne();
                        }
    
                    }
                }
                return test;
            }
    
        }

    七、线程池

    ThreadPool.QueueUserWorkItem();//里面传入委托。还可以在后面添加一个Object的参数,这个参数的意义就是实现线程的参数化。

        WaitHandle 线程间的通讯。他有两个子类是经常用到的。

        ManualResetEvent:这个就相当于与是手动去操作。把线程间的通讯表示成开门关门的话。当创建 ManualResetEvent man=new ManualResetEvent(false)

    ;这个类的时候,false就代表初始化的时候就已经关上门了。当线程中调用 man.WaitOne();就带表了这个线程一直在等待(WaitOne()可以添加参数,表示等待的时间)

    等待着开门。当线程调用man.Set();的时候,该线程就开门了,线程就会继续往下执行。man.Reset();手动关门

        第二个子类是AutoResetEvent。这个就是在执行WaitOne()线程等待的时候,若发现开门之后,当执行完线程后会自动把门给关闭。

  • 相关阅读:
    删除 AP 发票相关脚本
    js框架简明
    16 款最流行的 JavaScript 框架
    八款你不得不知的开源前端JS框架
    ExtJS面向对象
    js6类和对象
    js模拟类
    js实现继承
    Html中各种空格的显示
    常用快速原型设计工具大比拼、原型设计工具哪个好用
  • 原文地址:https://www.cnblogs.com/xiaojunwu/p/12704454.html
Copyright © 2011-2022 走看看