多线程学习(一)

一、使用线程的理由

1、可以使用线程将代码同其他代码隔离,提高应用程序的可靠性。

2、可以使用线程来简化编码。

3、可以使用线程来实现并发执行。

二、基本知识

1、进程与线程:进程作为操作系统执行程序的基本单位,拥有应用程序的资源,进程包含线程,进程的资源被线程共享,线程不拥有资源。

2、前台线程和后台线程:通过Thread类新建线程默认为前台线程。当所有前台线程关闭时,所有的后台线程也会被直接终止,不会抛出异常。

3、挂起(Suspend)和唤醒(Resume):由于线程的执行顺序和程序的执行情况不可预知,所以使用挂起和唤醒容易发生死锁的情况,在实际应用中应该尽量少用。

4、阻塞线程:Join,阻塞调用线程,直到该线程终止。

5、终止线程:Abort:抛出 ThreadAbortException 异常让线程终止,终止后的线程不可唤醒。Interrupt:抛出 ThreadInterruptException 异常让线程终止,通过捕获异常可以继续执行。

6、线程优先级:AboveNormal BelowNormal Highest Lowest Normal,默认为Normal。

三、线程的使用

线程函数通过委托传递,可以不带参数,也可以带参数(只能有一个参数),可以用一个类或结构体封装参数。

四、线程池

由于线程的创建和销毁需要耗费一定的开销,过多的使用线程会造成内存资源的浪费,出于对性能的考虑,于是引入了线程池的概念。

线程池维护一个请求队列,线程池的代码从队列提取任务,然后委派给线程池的一个线程执行,线程执行完不会被立即销毁,这样既可以在后台执行任务,又可以减少线程创建和销毁所带来的开销。

线程池线程默认为后台线程(IsBackground)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //无参数
            Thread t1 = new Thread(new ThreadStart(GetName1));
            t1.IsBackground = true;
            t1.Start();

            //多个参数,使用类内部调用,多个参数还可以使用 struct 结构
            UserInfo userInfo = new UserInfo() { Name = "jack", Address = "ShangHai" };
            Thread t2 = new Thread(new ThreadStart(userInfo.GetUserInfo));
            t2.IsBackground = true;
            t2.Start();

            //单个参数,使用线程调用,参数须是object类型
            Thread t3 = new Thread(new ParameterizedThreadStart(GetName2));
            t3.IsBackground = true;
            t3.Start("rolly");

            //加入到线程池队列中,多个参数,使用 类 或者 struct 结构
            ThreadPool.QueueUserWorkItem(GetUserInfo, userInfo);

            Console.ReadLine();
        }

        //无参数1
        public static void GetName1()
        {
            Console.WriteLine("无参数1:My name is Jay!");
        }

        //有一个参数,参数须是object类型
        public static void GetName2(object Name)
        {
            Console.WriteLine("有参数,使用线程调用:My name is " + Name.ToString());
        }

        //加入到线程池中,多个参数,使用 类 或者 struct 结构,参数须是object类型
        public static void GetUserInfo(object obj)
        {
            //强转
            UserInfo model = (UserInfo)obj;
            Console.WriteLine("多个参数,使用线程调用:My name is " + model.Name + ", Address: " + model.Address);
        }
    }

    public class UserInfo
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public void GetUserInfo()
        {
            Console.WriteLine("多个参数 类内部自己调用:My name is " + Name + ", Address: " + Address);
        }
    }
}

五、Task类

使用ThreadPool的QueueUserWorkItem()方法发起一次异步的线程执行很简单,但是该方法最大的问题是没有一个内建的机制让你知道操作什么时候完成,有没有一个内建的机制在操作完成后获得一个返回值。为此,可以使用System.Threading.Tasks中的Task类。

构造一个Task<TResult>对象,并为泛型TResult参数传递一个操作的返回类型。

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000);
            t.Start();
            t.Wait();
            Console.WriteLine(t.Result);
            Console.ReadKey();
        }

        private static Int32 Sum(Int32 n)
        {
            Int32 sum = 0;
            for (; n > 0; --n)
                checked{ sum += n;} //结果太大,抛出异常
            return sum;
        }
    }
}

一个任务完成后,它可以启动另一个任务,下面重写了前面的代码,不阻塞任何线程。

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000);
            t.Start();
            //t.Wait();
            Task cwt = t.ContinueWith(task => Console.WriteLine("The result is {0}",t.Result));
            Console.ReadKey();
        }

        private static Int32 Sum(Int32 n)
        {
            Int32 sum = 0;
            for (; n > 0; --n)
                checked{ sum += n;} //结果溢出,抛出异常
            return sum;
        }
    }
}

六、委托异步执行

委托的异步调用:BeginInvoke() 和 EndInvoke()

namespace Test
{
    public delegate string MyDelegate(object data);
    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate mydelegate = new MyDelegate(TestMethod);
            IAsyncResult result = mydelegate.BeginInvoke("Thread Param", TestCallback, "Callback Param");

            //异步执行完成
            string resultstr = mydelegate.EndInvoke(result);
        }

        //线程函数
        public static string TestMethod(object data)
        {
            string datastr = data as string;
            return datastr;
        }

        //异步回调函数
        public static void TestCallback(IAsyncResult data)
        {
            Console.WriteLine(data.AsyncState);
        }
    }
}

七、线程同步

  1)原子操作(Interlocked):所有方法都是执行一次原子读取或一次写入操作。

  2)lock()语句:避免锁定public类型,否则实例将超出代码控制的范围,定义private对象来锁定。

  3)Monitor实现线程同步

    通过Monitor.Enter() 和 Monitor.Exit()实现排它锁的获取和释放,获取之后独占资源,不允许其他线程访问。

    还有一个TryEnter方法,请求不到资源时不会阻塞等待,可以设置超时时间,获取不到直接返回false。

  4)ReaderWriterLock

    当对资源操作读多写少的时候,为了提高资源的利用率,让读操作锁为共享锁,多个线程可以并发读取资源,而写操作为独占锁,只允许一个线程操作。

  5)事件(Event)类实现同步

    事件类有两种状态,终止状态和非终止状态,终止状态时调用WaitOne可以请求成功,通过Set将时间状态设置为终止状态。

    1)AutoResetEvent(自动重置事件)

    2)ManualResetEvent(手动重置事件)

  6)信号量(Semaphore)

      信号量是由内核对象维护的int变量,为0时,线程阻塞,大于0时解除阻塞,当一个信号量上的等待线程解除阻塞后,信号量计数+1。

      线程通过WaitOne将信号量减1,通过Release将信号量加1,使用很简单。

  7)互斥体(Mutex)

      独占资源,用法与Semaphore相似。

  8)跨进程间的同步

      通过设置同步对象的名称就可以实现系统级的同步,不同应用程序通过同步对象的名称识别不同同步对象。

来源:http://www.cnblogs.com/luxiaoxun/p/3280146.html

时间: 2024-07-28 14:19:49

多线程学习(一)的相关文章

Java多线程学习(吐血超详细总结)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程

Qt多线程学习:创建多线程

[为什么要用多线程?] 传统的图形用户界面应用程序都仅仅有一个运行线程,而且一次仅仅运行一个操作.假设用户从用户界面中调用一个比較耗时的操作,当该操作正在运行时,用户界面一般会冻结而不再响应.这个问题能够用事件处理和多线程来解决. [Linux有线程的概念吗?] 传统的UNIX系统也支持线程的概念,但一个进程里仅仅同意有一个线程,这样多线程就是多进程.Linux下的Posix线程(pthreads)是一种轻量级的进程的移植性实现,线程的调度由内核完毕,每一个线程都有自己的编号.假设使用线程,整体

Java多线程学习(详细)

一.进程与线程的区别 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小.(线程是cpu调度的最小单位) 线程和进程一样分为五个阶段:创建.就绪.运行.阻塞.终止.     多进程是指操作系统能同时运行多个任务(程序).     多线程是指在同一程序中有多个顺序流在执行. 在java中要想实现多线程,有两种手段,一

C#多线程学习(一) 多线程的相关概念

什么是进程?    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数. 什么是多线程?    多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务. 多线程的好处:    可以提

C#多线程学习(六) 互斥对象

C#多线程学习(六) 互斥对象 如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对象,即:System.Threading 命名空间中的 Mutex 类. 我们可以把Mutex看作一个出租车,乘客看作线程.乘客首先等车,然后上车,最后下车.当一个乘客在车上时,其他乘客就只有等他下车以后才可以上车.而线程与Mutex对象的关系也正是如此,线程使用Mutex.WaitOne()方法等待Mutex对象被释放,如果它等待的Mutex对象被释放了,它就自动拥有这个对象,直到它调用Mute

C#多线程学习(一) 多线程的相关概念(转)

什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数. 什么是多线程?多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务. 多线程的好处:可以提高CPU的利用率.在多线程程序中

多线程学习 + o2o简识

多线程学习: ( 1.NSThread 2.NSOperationQueue 3.GCD ) 1.进程和线程: 进程:app无法独立运行,需要分配内存空间,每个app至少有一个进程,是应用程序的开始(缺点:不能同时执行) 线程:是应用程序运行的最小单元可以多个线程并发同时执行,防止主线程堵塞,增加运行效率. 主线程:又叫UI主线程,程序运行都是在主线程加载,加载视图,但不可加载数据,因为请求网络数据的时间特别长,会出现空白现象(更新UI一定要在主线程中写) 子线程:没法加载UI,UI只在主线程中

java多线程学习(3)

1)竞争条件 在实际的多线程应用中,通常会有两个或多个线程需要对共同的对象进行共享访问,如果两个线程访问相同的对象,而且每一个都调用了一个会改变对象状态的方法, 那么,线程就会相互倾轧.根据各个线程访问数据的不同顺序,可能会产生腐蚀现象.这种情况通常称为竞争条件. 2)同步 为了多个线程对共享数据的腐蚀,就需要对数据的存取实现同步:常用的同步方法有3种: 1.Reenlock 用Reenlock保护代码块的基本机构如下: 1 Lock myLock=new ReenLock; 2 3 myLoc

Java多线程学习

写在前面的话:此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢?如果你觉得此文很简单,那推荐你看看Java并发包的的线程池(Java并发编程与技术内幕:线程池深入理解),或者看这个专栏:Java并发编程与技术内幕.你将会对Java里头的高并发场景下的线程有更加深刻的理解. 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线

java多线程学习(2)

1)Callable和Future Runnable封装一个异步运行的任务:可以当成一个没有任何参数和返回值的异步方法,Callable和 Runnable类似,但是它有返回值和参数. Callable接口是一个参数化的类型,只有一个方法call. 1 public interface Callable<V> 2 3 { 4 5 V call()throws Exception; 6 7 } 类型参数v是指返回值的类型,例如Callable<Integer>代表最终返回一个Inte