一.进程和线程的概念
1.进程概念
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
2.线程概念
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
3.关系
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
其实看这么多概念总结起来就几句话:
1.一个程序可以由多个进程组成,一个进程可以由多个线程组成
2.进程是有内存空间的,线程是没有内存空间的,所有线程共享进程的内存空间
3.线程极大地提高了程序的运行效率,但也容易出现很多问题
二.前台线程和后台线程
前台线程:应用程序必须运行完所有的前台线程才可以退出
后台进程: 应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
class MainClass
{
private static int a=20;
private static int ticker=100;
private static string str="------";
//从main方法开始的就是主线程(是前台线程)
public static void Main (string[] args)
{
Console.WriteLine ("主线程开始");
//参数类型为委托
Thread ptherad = new Thread (Worker1);
//true为后台程序,默认为前台线程
ptherad.IsBackground = true;
ptherad.Start ();
//把后台线程加进来,主线程被阻塞,执行后台线程
ptherad.Join ();//Join是连接的意思,和直接调用一个方法类似
// Thread.Sleep (4000);
{
private static int a=20;
private static int ticker=100;
private static string str="------";
//从main方法开始的就是主线程(是前台线程)
public static void Main (string[] args)
{
Console.WriteLine ("主线程开始");
//参数类型为委托
Thread ptherad = new Thread (Worker1);
//true为后台程序,默认为前台线程
ptherad.IsBackground = true;
ptherad.Start ();
//把后台线程加进来,主线程被阻塞,执行后台线程
ptherad.Join ();//Join是连接的意思,和直接调用一个方法类似
// Thread.Sleep (4000);
Thread thread = new Thread (Worker2);
thread.Start ("aa");
thread.Join ();
Console.WriteLine ("从主程退出");
//输出结果不会执行后台线程的那句输出,
//主线程一旦结束,后台线程也会退出
//如果是前台线程必定要执行完才退出。
thread.Start ("aa");
thread.Join ();
Console.WriteLine ("从主程退出");
//输出结果不会执行后台线程的那句输出,
//主线程一旦结束,后台线程也会退出
//如果是前台线程必定要执行完才退出。
}
public static void Worker1()
{
//Thread代表的这个后台线程,如果写到主线程里边,那么代表主线程
Thread.Sleep (3000);//3s 单位为毫秒,
Console.WriteLine ("后台线程退出:Worker1");
}
public static void Worker2(object data)
{
// Thread.Sleep (3000);
Console.WriteLine (data.ToString());
Console.WriteLine ("thread线程退出");
a *= 2;
Console.WriteLine (a);
}
}
{
//Thread代表的这个后台线程,如果写到主线程里边,那么代表主线程
Thread.Sleep (3000);//3s 单位为毫秒,
Console.WriteLine ("后台线程退出:Worker1");
}
public static void Worker2(object data)
{
// Thread.Sleep (3000);
Console.WriteLine (data.ToString());
Console.WriteLine ("thread线程退出");
a *= 2;
Console.WriteLine (a);
}
}
三.线程池
1.用来存放应用程序使用的线程的集合,可以理解为存放线程的 地方,这种集中存放的方式有利于管理线程。
2.当应用程序想要执行一个异步操作时,需要调用QueueUserWorkItem方法将对应的任务添加到线程 池中。线程池会从队列中提取任务,并且将其委派给线程池中 的线程执行。
3.如果线程池中没有空闲的线程,就会创建一个新的线程去提取
新的任务。当线程完成某个任务时候,线程也不会被销毁,而是返回
到线程池中,等待另外一个请求。
4.默认都是后台线程。
//线程池(都是后台线程)
Console.WriteLine ("主线程开始");
//1.线程必须有一个参数(为object类型),
//2.无返回值(void),
//3.操作为异步执行(同时执行)
ThreadPool.QueueUserWorkItem (Worker1);
ThreadPool.QueueUserWorkItem(Worker2,"date");
//获取线程组合ID
Console.WriteLine (Thread.GetDomainID());
Console.WriteLine ("从主程退出");
Console.WriteLine (a);
Console.WriteLine ("主线程开始");
//1.线程必须有一个参数(为object类型),
//2.无返回值(void),
//3.操作为异步执行(同时执行)
ThreadPool.QueueUserWorkItem (Worker1);
ThreadPool.QueueUserWorkItem(Worker2,"date");
//获取线程组合ID
Console.WriteLine (Thread.GetDomainID());
Console.WriteLine ("从主程退出");
Console.WriteLine (a);
public static void Worker1(object date)
{
//Thread代表的这个后台线程,如果写到主线程里边,那么代表主线程
// Thread.Sleep (3000);//3s 单位为毫秒,
Console.WriteLine ("后台线程退出:Worker1");
a++;
Console.WriteLine (a);
}
public static void Worker2(object data)
{
// Thread.Sleep (3000);
Console.WriteLine (data.ToString());
Console.WriteLine ("thread线程退出");
a *= 2;
Console.WriteLine (a);
}
{
//Thread代表的这个后台线程,如果写到主线程里边,那么代表主线程
// Thread.Sleep (3000);//3s 单位为毫秒,
Console.WriteLine ("后台线程退出:Worker1");
a++;
Console.WriteLine (a);
}
public static void Worker2(object data)
{
// Thread.Sleep (3000);
Console.WriteLine (data.ToString());
Console.WriteLine ("thread线程退出");
a *= 2;
Console.WriteLine (a);
}
四.同步进程
线程同步技术是指多线程程序中,为了保证后者线程,只有等待前者线程完成之后才能继续执行。就好比买票,前面的人没买到票之前,后面的人必须等待。
对线程技术存在的隐患:
当我们去访问一个共享资源的时候,有可能会同时去访问一个共享资源,这会破坏资源中的数据。
Console.WriteLine ("主线程开始");
Thread thread1 = new Thread (SaleTicketThread1);
Thread thread2 = new Thread (SaleTicketThread2);
thread1.IsBackground =true;
thread2.IsBackground=true;
thread1.Start ();
thread2.Start ();
Thread.Sleep (2000);
Console.WriteLine ("从主程退出");
public static void SaleTicketThread1()
{
while (true) {
//监控(当str第一次被监控时会给变量str锁住,其他监控这个变量就不能再执行语句,挂起在那,
//当第一次监控执行完成后,会执行finally语句,给这个变量解锁,那么其他监控就可以继续执行语句)
try{
Monitor.Enter(str);
if (ticker>0) {
Console.WriteLine ("1出票:{0}",ticker--);
}
}finally{
Monitor.Exit (str);
}
}
}
public static void SaleTicketThread2()
{
while (true) {
try{
Monitor.Enter(str);
if (ticker>0) {
Console.WriteLine ("2出票:{0}",ticker--);
}
}finally{
Monitor.Exit (str);
}
}
}
//当第一次监控执行完成后,会执行finally语句,给这个变量解锁,那么其他监控就可以继续执行语句)
try{
Monitor.Enter(str);
if (ticker>0) {
Console.WriteLine ("1出票:{0}",ticker--);
}
}finally{
Monitor.Exit (str);
}
}
}
public static void SaleTicketThread2()
{
while (true) {
try{
Monitor.Enter(str);
if (ticker>0) {
Console.WriteLine ("2出票:{0}",ticker--);
}
}finally{
Monitor.Exit (str);
}
}
}