多线程学习整理

一、 多线程的概念

1.线程和进程

线程和进程是现代操作系统的重要概念。

前者是应用程序的实例,一个正在运行的应用程序在操作系统中被视为一个进程。进程拥有自身独立的资源,进程之间相互隔离,互不干扰。为了使多个任务互不干扰,每个进程都拥有独立的虚拟地址空间,代码段,数据段以及堆栈,另外进程还占了各种系统资源(如文件,窗体对象,环境变量等等)。

线程是操作系统分配处理器时间的基本单元。一组指令的集合,可以在程序中独立的执行,也被称为“轻量级进程”或者“微进程”。一个进程可以包含一个或者多个线程。线程共享其所属进程所拥有的资源,可以访问进程的内存区域和代码段。同时线程还拥有各自的局部变量和独立的栈空间。每个进程至少拥有一个进程来执行它的代码,如果没有没有线程来执行,系统就会自动撤销该进程和它的地址空间。

2.线程的生命周期和状态

从线程被创建到被终止称为线程的生命周期。

在线程被创建以后,该线程出于开始状态。

一般情况下,线程会从开始状态转为就绪状态,只有出于就绪状态的线程才会被操作系统按照一定的调度算法进行调度,从而转入运行状态。

出于运行状态的线程也会在一定的时间(如时间片用完)被调度出运行状态进入就绪状态,等待下次调度。

处于运行状态的线程也可能因为等待某个资源,或者被人为的设定进入休眠状态,直至需要的资源被释放或者是人为地休眠指令结束,就会转入就绪状态。

处于运行状态的线程会因指令执行完毕,或者被人为地终止而进入终止状态。

3.线程的优先级

每个线程都被赋予了一定的优先级。在线程被调度执行的时候,回报根据该线程的优先级来进行调度,一般来说,优先级搞得线程会被优先调度执行。线程的优先级可以通过Thread类Priority属性设置,Priority属性是一个ThreadPriority型枚举,列举了5个优先等级:AboveNormal、BelowNormal、Highest、Lowest、Normal。普通线程的优先级默认为Normal;如果想有更高的优先级,可设置为AboveNormal或Highest;如果想有较低的优先级,可设置为BelowNormal或Lowest。

二、线程创建与控制

1.创建和启动线程

命名空间:

using System;

using System.Threading;

a.线程用Thread类来创建, 通过ThreadStart委托来指明方法从哪里开始运行,下面是ThreadStart委托如何定义的:

public delegate void ThreadStart();

调用Start方法后,线程开始运行,线程一直到它所调用的方法返回后结束。下面是一个例子,使用了C#的语法创建TheadStart委托。

static void Main(string[] args)

        {

            ThreadStart ts = new ThreadStart(Print);

            Thread t = new Thread(ts);

            t.Start();

            Print();

            Console.ReadLine();

        }

        static void Print()

        {

            Console.WriteLine("Hello World!");

        }

b.将数据传入ThreadStart中

在创建托管的线程时,在该线程上执行的方法将通过一个传递给 Thread 构造函数的 ThreadStart 委托或 ParameterizedThreadStart 委托来表示。在调用 System.Threading.Thread.Start 方法之前,该线程不会开始执行。执行将从 ThreadStart 或 ParameterizedThreadStart 委托表示的方法的第一行开始。

public delegate void ParameterizedThreadStart (object obj);

static void Main(string[] args)

        {

            Thread t = new Thread(new ParameterizedThreadStart(Print));

            t.Start("线程a");

            //Thread.Sleep(20);

            Print("主线程");

            Console.ReadLine();

        }

        static void Print(Object obj)

        {

            Console.WriteLine(obj.ToString());

        }

C.线程的一些属性

2.控制线程

当执行一个线程后,该线程会经历一个生命周期,及开始,就绪,运行,休眠,终止等。这些状态可以通过线程的ThreadState属性来获取。

三、多线程的同步

1.线程安全

1.1争用条件

两个或者多个线程同事访问统一数据或者资源时,会导致不符合要求或者无法预期的结果。

a.当线程们引用了一些公用的目标实例的时候,他们会共享数据.

class ThreadTest

    {

        bool done;

        static void Main(string[] args)

        {

            ThreadTest tt = new ThreadTest();  

            new Thread(tt.Print).Start();

            tt.Print();

            Console.ReadLine();

        }

        void Print()

        {

            if (!done)

            {

                done = true;

                Console.WriteLine("Hello World!");

            }

        }

    }

b.静态字段提供了另一种在线程间共享数据的方式.

class ThreadTest

    {

        static bool done;

        static void Main(string[] args)

        {

            new Thread(Print).Start();

            Print();

            Console.ReadLine();

        }

        static void Print()

        {

            if (!done)

            {

                done = true;

                Console.WriteLine("Hello World!");

            }

        }

}

上述两个例子足以说明, 另一个关键概念, 那就是线程安全. 输出实际上是不确定的:它可能(虽然不大可能) , 可以被打印两次。然而,如果我们在Print方法里调换指令的顺序, 打印两次的机会会大幅地上升:

  if (!done)

            {

                Console.WriteLine("Hello World!");

                done = true;

            }

补救措施是当读写公共字段的时候,提供一个排他锁

class ThreadTest

    {

        static bool done;

        static object locker = new object();

        static void Main(string[] args)

        {

            new Thread(Print).Start();

            Print();

            Console.ReadLine();

        }

        static void Print()

        {

            lock (locker )

            {

                if (!done)

                {

                    Console.WriteLine("Hello World!");

                    done = true;

                }

            }

        }

}

当两个线程争夺一个锁的时候(在这个例子里是locker),一个线程等待,或者说被阻止到那个锁变的可用。在这种情况下,就确保了在同一时刻只有一个线程能进入临界区。

1.2死锁

如果多个线程彼此等待对方释放其所占用的资源,则也会遇到线程安全的问题。这种对线程的阻塞称为死锁。

2.线程同步策略

2.1同步上下文

上下文是一组有序的属性或者规则,这组属性或规则将类似的对象绑定在一起。同步上下文策略就是直接使用.net提供的SynchronizationAttribute类的构造函数对驻留上下文中,符合上下文规则的对象启用简单的自动同步,确保同一时刻只有一个线程可以访问该对象。该策略不处理静态字段和方法的同步。

可以使用SynchronizationAttribute属性,为ContextBoundObject的派生对象启用简单的自动同步,该属性为当前上下文和所有共享同一实例的上下文强行创建一个同步域。将该属性应用于某一个对象时,在共享该属性的实例的所有上下文中只能有一个线程执行,多个线程可以访问方法和字段,但在任一时刻只允许一个线程访问。

2.2同步代码区

Monitor类和Lock关键字

Monitor类用于同步代码区,其思想是首先使用Monitor.Enter()方法获得一个锁,然后使用Monitor.Exit()方法释放该锁。一个线程一旦获得重要代码区的锁,其他的线程就要等到该锁被释放后才能使用该代码区。这样就能通过同步最少量的代码,实现最大限度的并发。

使用Lock关键字同样可以获取一个Monitor锁。

2.3手工同步

ReaderWriterLock类等等

ReaderWriterLock类提供单个进程写和多个进程度的控制机制,优点是资源开销非常低。该类有两个锁:读线程锁和写线程锁。当请求写线程锁后,在写线程取得访问权之前,不会接受任何新的读线程,从而实现多个线程在任何时刻执行读方法,或允许单个线程在任何时刻执行写方法。

时间: 2024-11-03 16:55:01

多线程学习整理的相关文章

多线程学习 + o2o简识

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

HttpClient学习整理

HttpClient简介 HttpClient 功能介绍     1. 读取网页(HTTP/HTTPS)内容     2.使用POST方式提交数据(httpClient3)     3. 处理页面重定向     4. 模拟登录开心网     5. 提交XML格式参数     6. 访问启用认证的页面     7. 多线程模式下使用httpclient httpClient完整封装 HttpClient简介 HTTP 协议可能是现在 Internet 上使用得最多.最重要的协议了,越来越多的 Ja

Spring?IOC设计原理解析:本文乃学习整理参考而来

Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. IoC容器的初始化 1. XmlBeanFactory(屌丝IOC)的整个流程 2. FileSystemXmlApplicationContext 的IOC容器流程 1.高富帅IOC解剖 2. 设置资源加载器和资源定位 3.AbstractApplicationContext的refresh函数载入

2019.09.09学习整理

2019.09.09学习整理 基于socket套接字的UDP协议 UDP套接字示例 客户端 import socket cli = socket.socket(type=socket.SOCK_DGRAM) while True: msg = input('>>:').strip() cli.sendto(msg.encode('utf-8'), ('127.0.0.1', 8003)) data,ser_addr=cli.recvfrom(1024) cli.close() 服务端 impo

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

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

ijwmh1-2-以前学习整理出来的学习内容--什么是变量1整型变量

崧闱旭 ijwmh1-2-以前学习整理出来的学习内容--什么是变量1整型变量

java中反射学习整理

转载请注明:http://blog.csdn.net/j903829182/article/details/38405735 反射主要是指程序可以访问,检测和修改它本身的状态或行为的一种能力. java中反射是一种强大的工具,它能够创建灵活的代码,这些代码可以在运行时装载,无须在组件之间进行链接.反射允许在编写与执行时,使程序能够接入到jvm中的类的内部信息,而不是源代码中选定的类协作的代码.这使反射成为构建灵活应用代码的主要工具.需要注意的是,如果使用不当,反射的成本会很高. package

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

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

AJAX学习整理二之简单实例

做了几个简单的实例,加载txt文本内容.加载xml文件内容,把xml文本内容转换成html表格显示.废话不多说,直接贴代码: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/html"> <head>     <title>通过ajax获取文本内容</title>     <meta charset="utf-8">     <scr