概述

  上一章节中和大家分享了线程的基础使用方法。在这一章中来和大家分享线程的一些常用方法。

  主要包括:线程阻塞,线程终止,线程锁三方面。

Thread 的 Sleep 和 Join 方法

Thread.Sleep:将当前线程阻塞指定的毫秒数。

Console.WriteLine("主线程执行时间:{0}", DateTime.Now.ToString());
Thread.Sleep(4000); //阻塞4s
Console.WriteLine("主线程执行时间:{0}", DateTime.Now.ToString());

输出结果:

两次打印输出间隔为:4秒。线程阻塞以毫秒为单位。

Sleep也支持TimeSpan,将当前线程阻塞指定的时间。

Thread.Join:阻塞调用线程,直到某个线程终止时为止。

第一次看到msdn的解释一下子没有反应过来。这里我们可以理解为:分别开启三个线程t1,t2,t3对t1,t2,t3依次调用Join后,程序会先把线程t1执行完后,在执行线程t2的内容..以此类推到t3。

如下代码所示:

 var watch = Stopwatch.StartNew();
Thread t1 = new Thread(() =>
{
Thread.Sleep();
Console.WriteLine("t1 is ending.");
});
t1.Start();
t1.Join();
Console.WriteLine("t1.Join() returned."); Thread t2 = new Thread(() =>
{
Thread.Sleep();
Console.WriteLine("t2 is ending.");
});
t2.Start();
t2.Join();
Console.WriteLine("t2.Join() returned."); Console.WriteLine("总结:Join()会阻塞调用线程直到调用线程结束." + watch.ElapsedMilliseconds);

输出结果:

程序先执行线程t1里的内容,让线程阻塞4秒,因为线程t1调用Join()方法阻塞调用线程,直到t1线程执行完成。

然后打印出“t1.Join() returned.”。在执行t2线程,直到t2线程执行完后才执行主线程打印的内容。

这里不难看出他们是按顺序来执行的。

如果我们不使用join()方法看看他的输出结果会是怎么样:

var watch = Stopwatch.StartNew();
Thread t1 = new Thread(() =>
{
Thread.Sleep();
Console.WriteLine("t1 is ending.");
});
t1.Start();
//t1.Join();
Console.WriteLine("t1.Join() returned."); Thread t2 = new Thread(() =>
{
Thread.Sleep();
Console.WriteLine("t2 is ending.");
});
t2.Start();
//t2.Join();
Console.WriteLine("t2.Join() returned."); Console.WriteLine("总结:Join()会阻塞调用线程直到调用线程结束." + watch.ElapsedMilliseconds);

输出结果:

此时主线程会先开启t1线程,t1被阻塞4秒 。所以t1线程里的内容没有被打印出来,会在4秒后打印。

这时主线程不会等待t1线程完成后在执行下面代码,主线程会继续向下执行打印出“t1.Join() returned.”

然后开启t2线程,t2线程同样也会被阻塞了1秒。

主线程会继续向下执行打印出其他内容。最后陆续由线程t2,线程t1打印出各自对应信息。

Thread 的 Abort 和 Interrupt

Thread.Abort:在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。

 Thread t1 = new Thread(() =>
{
for (int i = ; i < ; i++)
{
try
{
Thread.Sleep();
}
catch (ThreadAbortException ex)
{
Console.WriteLine("Abort终止线程.当前线程名称:{0}.状态:{1}", Thread.CurrentThread.Name, Thread.CurrentThread.ThreadState);
}
Console.WriteLine("我在运行着!");
} });
t1.Name = "t1";
t1.Start();
Thread.Sleep();
t1.Abort();
Console.WriteLine("当前线程名称:{0}.状态:{1}", t1.Name, t1.ThreadState);

输出结果:

开启t1线程,阻塞800毫秒打印了二次“我在运行着!”,准备运行第三次时。

阻塞1000毫秒的主线程调用Abort()方法直接把t1线程给干掉了.他再也没有站起来执行第四次打印。

当前t1线程直接被干掉。

Thread.Abort:中断处于 WaitSleepJoin 线程状态的线程。

 Thread t2 = new Thread(() =>
{
for (int i = ; i < ; i++)
{
try
{
Thread.Sleep();
Console.WriteLine("我在运行着!");
}
catch (ThreadInterruptedException ex)
{
Console.WriteLine("Interrupt终止线程.当前线程名称:{0}.状态:{1}", Thread.CurrentThread.Name, Thread.CurrentThread.ThreadState);
}
}
});
t2.Name = "t2";
t2.Start();
Thread.Sleep();
t2.Interrupt();
Console.WriteLine("当前线程名称:{0}.状态:{1}", t2.Name, t2.ThreadState);
Console.Read();

输出结果:

开启t2线程,阻塞800毫秒打印了二次“我在运行着!”,准备运行第三次时。

阻塞1000毫秒的主线程调用Interrupt()方法把t2线程第三次阻塞中断,但t2线程并未被终止,继续在运行。

直到线程运行结束。

线程锁

Monitor.Enter() 和 Monitor.Exit() :在指定对象上获取排他锁。

先来看一下多线程在访问共享变量未加锁的情况:

 int number = ;
//没加锁
for (int i = ; i < ; i++)
{
new Thread(() =>
{
Thread.Sleep(); //堵塞线程.不然线程执行时间太短,体现不出并发效果
Console.WriteLine(number);
number++;
}).Start();
}

输出结果:

我们发现开启10个线程去访问一个共享变量number,在没有加锁的情况下有5个线程访问到的值都是:0。

当多个线程存在并发的时,难免会碰到相互冲突的事情。这个时候我们就会用到锁。

Lock()方法在MSIL中会被编译成 Monitor.Enter()和Monitor.Exit()。

在来看看多线程在访问共享变量加锁的情况:

 //加锁
int number = ;
object objLock = new object();
for (int i = ; i < ; i++)
{
new Thread(() =>
{
Thread.Sleep(); //堵塞线程.不然线程执行时间太短,体现不出并发效果 Monitor.Enter(objLock);
Console.WriteLine(number);
number++;
Monitor.Exit(objLock);
}).Start();
}

输出结果:

加锁后我们发现多线程在访问共享变量采用的是排他模式。

每次访问共享变量都只有一个线程,其他线程只能等待别的线程访问完成后才能进行访问。[Monitor.Enter()和Monitor.Exit()必须是成对使用.]

Monitor.Wait() / Monitor.Pulse() : 释放对象上的锁并阻止当前线程,直到它重新获取该锁。/通知等待队列中的线程锁定对象状态的更改。

 object objLock = new object();
new Thread(() =>
{
Thread.Sleep();
Monitor.Enter(objLock); Console.WriteLine("我是第一个出现");
Console.WriteLine("我是第二个出现");
Monitor.Wait(objLock);
Console.WriteLine("完成1");
Monitor.Pulse(objLock); Monitor.Exit(objLock); }).Start(); new Thread(() =>
{
Thread.Sleep();
Monitor.Enter(objLock); Monitor.Pulse(objLock);
Console.WriteLine("我是第三个出现");
Console.WriteLine("我是第四个出现");
Monitor.Wait(objLock);
Console.WriteLine("完成2"); Monitor.Exit(objLock);
}).Start();

输出结果:

C# 线程--第二线程方法的更多相关文章

  1. C#中的几个线程同步对象方法

    在编写多线程程序时无可避免会遇到线程的同步问题.什么是线程的同步呢? 举个例子:如果在一个公司里面有一个变量记录某人T的工资count=100,有两个主管A和B(即工作线程)在早一些时候拿了这个变量的 ...

  2. 线程池之ThreadPool类与辅助线程 - <第二篇>

    一.CLR线程池 管理线程开销最好的方式: 尽量少的创建线程并且能将线程反复利用(线程池初始化时没有线程,有程序请求线程则创建线程): 最好不要销毁而是挂起线程达到避免性能损失(线程池创建的线程完成任 ...

  3. 线程的实现方法以及区别 extends Thread、implements Runable

    /** 线程存在于进程当中,进程由系统创建. 创建新的执行线程有两种方法 注意:   线程复写run方法,然后用start()方法调用,其实就是调用的run()方法,只是如果直接启动run()方法, ...

  4. python之路--线程的其他方法

    一 . current_thread的用法 import threading import time from threading import Thread, current_thread def ...

  5. 转载 线程池之ThreadPool类与辅助线程 - <第二篇>

    http://www.cnblogs.com/kissdodog/archive/2013/03/28/2986026.html 一.CLR线程池 管理线程开销最好的方式: 尽量少的创建线程并且能将线 ...

  6. 重点:怎样正确的使用QThread类(注:包括推荐使用QThread线程的新方法QObject::moveToThread)

    背景描述: 以前,继承 QThread 重新实现 run() 函数是使用 QThread唯一推荐的使用方法.这是相当直观和易于使用的.但是在工作线程中使用槽机制和Qt事件循环时,一些用户使用错了.Qt ...

  7. day 34线程的其他方法,线程池

    线程的其他方法:  from threading import Thread,current_thread: currrent_thread().getName()  获取线程的名称 current_ ...

  8. Thread的中断机制(interrupt),循环线程停止的方法

    一.中断原理 中断线程 线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个 ...

  9. Java线程同步的方法

    如果向一个变量写值,而这个变量接下来可能会被另一个线程所读取,或者从一个变量读值,而它的值可能是前面由另一个线程写入的,此时就必须使用同步. sychronized Java语言的关键字,当它用来修饰 ...

随机推荐

  1. 如何让自己的电脑发布ASP http://jingyan.baidu.com/article/19192ad853224ce53f570748.html

    怎样在WIN7系统下安装IIS | 浏览:122821 | 更新:2012-03-03 14:07 | 标签:windows7 1 2 3 4 5 6 7 分步阅读 在此根据多年的网站开发经验,把如何 ...

  2. 【转】web测试内容及工具经典总结

    基于Web的系统测试在基于Web的系统开发中,如果缺乏严格的过程,我们在开发.发布.实施和维护Web的过程中,可能就会碰到一些严重的问题,失败的可能性很大.而且,随着基于Web的系统变得越来越复杂,一 ...

  3. node搜索codeforces 3A - Shortest path of the king

    发一下牢骚和主题无关: 搜索,最短路都可以     每日一道理 人生是洁白的画纸,我们每个人就是手握各色笔的画师:人生也是一条看不到尽头的长路,我们每个人则是人生道路的远足者:人生还像是一块神奇的土地 ...

  4. PI-webservice06-调用外部webservice过程中注意问题

    1,SAP与.NET系统之间通过webservice来进行数据交互的过程中,格式是有要求的,要求.NET发布出来的webservice中的数据是用list来进行传输的,不能用datatable和lis ...

  5. URAL 2056 Scholarship 水题

    ScholarshipTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view.a ...

  6. SAP BW 通过视图创建数据源(无单位)

    因业务明细表中数量没有单位,所以BW创建数据源时,需做增强 数据表: ZDB_H(抬头) ZDB_I(明细) ECC 系统中: 1.创建视图ZVDBWQ,因明细表中数量没有单位,所以创建视图时不包括数 ...

  7. php 常用正则表达式

    判断“正浮点数”: preg_match('/^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*) ...

  8. cocos2dx libjson

    libjson下载 http://sourceforge.net/projects/libjson/ 下载解压后改名成libjson,用到的是根目录下面的JSONOptions.h.libjson.h ...

  9. Android(java)学习笔记71:生产者和消费者之等待唤醒机制

    1. 首先我们根据梳理我们之前Android(java)学习笔记70中关于生产者和消费者程序思路: 2. 下面我们就要重点介绍这个等待唤醒机制: (1)第一步:还是先通过代码体现出等待唤醒机制 pac ...

  10. Android(java)学习笔记116:PC_Phone通信程序报错

    1.首先我写的程序代码如下: package com.himi.udpsend; import java.net.DatagramPacket; import java.net.DatagramSoc ...