标签:多线程
1、 进程:是操作系统结构的基础,一个正在执行的应用程序就是一个进程。进程包括运行中的程序和程序所使用到的内存和系统资源。一个进程是由多个线程组成的。
2、 线程:线程是进程中的一个单一的顺序控制流程,是程序执行的最小单元。每个线程都有自己的专有寄存器(栈指针、程序计数器等)。但是代码区是共享的,即不同的线程可以执行相同的函数。
3、 多线程:多线程是指在一个进程中包含有多个执行流,即在一个应用程序中可以运行多个不同的线程来执行不同的任务。
4、 多线程的好处:可以提高CPU的利用率。在一个多线程程序中,当其中某一个线程必须等待的时候,此时CPU可以运行其他的线程而不是等待这个线程结束之后再运行。这样便可以大大提高程序运行效率。
5、 在应用多线程时,要在程序的头部使用如下命名空间:
using System;
usingSystem.Threading;
6、 Thread类有如下几个重要的方法:
Start():启动线程;
Sleep(int):将当前线程暂停指定的毫秒数;
Abort():使用该方法来终止一个线程,终止后不可以恢复执行;
Suspend():暂时挂起正在执行的线程,以后还可以恢复;
Resume():恢复被Suspend()方法挂起的线程;
单线程问题演示
private void button1_Click(object sender,EventArgs e)
{
for (int i = 0; i < 10000000000; i++)
{
i += 1;
}
MessageBox.Show("出现后能拖动,提示没出现之前窗体不能被拖动");
}
原因:运行这个应用程序的时候,窗体应用程序自带一个叫做UI的线程,这个线程负责窗体界面的移动大小等。如果点击按钮则这个线程就去处理这个循环计算,而放弃了其它操作,故而窗体拖动无响应。这就是单线程带来的问题。
多线程演示
//创建线程
private void button1_Click(object sender, EventArgs e)
{
//ThreadStart是一个无参无返回值的委托。
ThreadStart ts = new ThreadStart(js);
//初始化Thread的新实例,并通过构造方法将委托ts做为参数赋初始值。
Thread td = new Thread(ts); //需要引入System.Threading命名空间
//运行委托
td.Start();
}
//创建的线程要执行的函数。
void js()
{
for (int i = 0; i < 1000000000; i++)
{
i += 1;
}
MessageBox.Show("提示出现前后窗体都能被拖动");
}
创建线程的4个步骤:
编写线程索要执行的方法。
引用System.Threading命名空间。
实例化Thread类,并传入一个指向线程所要运行方法的委托。
调用Start()方法,将该线程标记为可以运行的状态,但具体执行时间由cpu决定。
7、方法重入(多个线程执行同一个方法)
由于一个线程可与同属于一个进程的其他线程共享该进程所拥有的全部资源,所以多个线程同时执行同一个方法的情况是存在的。若不经过特别处理的话线程之间会争抢资源,使得数据计算结果混乱。
代码如下
public partial class 方法重入 : Form
{
public 方法重入()
{
InitializeComponent();
//设置TextBox类的这个属性是因为,开启ui线程,
//微软设置检测不允许其它线程对ui线程的数据进行访问,这里我们把检测关闭,也就允许了其它线程对ui线程数据的访问。
//如果检测不设置为False,则报错。
TextBox.CheckForIllegalCrossThreadCalls = false;
}
private void button1_Click(objectsender, EventArgs e)
{
textBox1.Text = "0";
//开启第一个线程,对js方法进行计算
ThreadStart ts = new ThreadStart(js);
Thread td = new Thread(ts);
td.Start();
//开启第二个线程,对js方法进行计算
ThreadStart ts1 = new ThreadStart(js);
Thread td1 = new Thread(ts1);
td1.Start();
}
//多线程要重入的方法。
void js()
{
int a = Convert.ToInt32(textBox1.Text);
for (int i = 0; i < 2000; i++)
{
a++;
textBox1.Text = a.ToString();
}
}
}
出错原因:两个进程同时计算这个方法,如果不相互干扰的话每个线程计算结果就应该是2000,。但是由于方法重入的原因,导致计算错乱。
解决办法:解决方法重入的方法是给该方法加锁,加锁的意思就是第一个线程取用过这个资源完毕后第二个线程再来取用此资源,形成排队取用的效果。
代码如下
//多线程要重入的方法,这里加锁。
void js()
{
lock (this)
{
int a =Convert.ToInt32(textBox1.Text);
for (int i = 0; i < 2000;i++)
{
a++;
textBox1.Text =a.ToString();
}
}
}
给方法加锁后,线程一前一后取用资源,避免了计算错乱的结果。第一个线程的计算结果为2000,第二个线程的计算就是从2000开始的,所以第二个线程的结果为4000.
8、 前台线程和后台线程
.Net的公用语言运行时可以区分两种不同类型的线程:前台线程和后台线程。这两者的区别就是:应用程序必须运行完所有的前台线程后才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有后台程序在应用程序退出时都会自动结束。
代码如下
privatevoid button1_Click(object sender, EventArgs e)
{
//开启一个线程,对js方法进行计算
ThreadStart ts2 = newThreadStart(js);
Thread td2 = new Thread(ts2);
td2.Start();
}
void js()
{
for (int i = 0; i < 2000000000;i++) //如果看不出效果这里的2后面多加0
{
i++;
}
MessageBox.Show("关闭了窗口我还是要出来的!");
}
原因:.Net环境使用Thread建立线程,线程默认为前台线程。即线程默认的属性IsBackground=false,而前台线程只要有一个在运行则应用程序不关闭,所以直到弹出消息框后应用程序才算是关闭。
解决办法:在代码中设置td2.IsBackground=true;
9、 线程执行带参数的方法
带单一参数(参数类型为object)
//创建一个执行带参数方法的线程
private void button1_Click(objectsender, EventArgs e)
{
//ParameterizedThreadStart这是一个参数类型为object的委托
ParameterizedThreadStart pts=newParameterizedThreadStart(SayHello);
Thread td2 = new Thread(pts);
td2.Start("张三"); //参数值先入这里
}
void SayHello(object name)
{
MessageBox.Show("你好,"+name.ToString()+"!");
}
带多个参数
//创建一个执行带多个参数的方法线程
private void button1_Click(objectsender, EventArgs e)
{
List<string> list = newList<string> { "张三", "李四", "王五" };
//ParameterizedThreadStart这是一个参数类型为object的委托
ParameterizedThreadStart pts=newParameterizedThreadStart(SayHello);
Thread td2 = new Thread(pts);
td2.Start(list); //参数值先入这里
}
void SayHello(object list)
{
List<string> lt = list asList<string>;
for (int i = 0; i < lt.Count;i++)
{
MessageBox.Show("你好," + lt[i].ToString() +"!");
}
}
本文出自 “Darren_liu技术空间” 博客,谢绝转载!
标签:多线程
原文地址:http://darren6.blog.51cto.com/9507876/1618610