关于Thread的那些事

1 : 你能够调用线程的实例方法Join来等待一个线程的结束.比如:

public static void MainThread()
{
Thread t = new Thread(Go);
t.Start();
t.Join();
Console.WriteLine("Thread t has ended!");
} static void Go()
{
for (int i = 0; i < 1000; i++)
Console.Write("y");
}

分析:在打印了1000个Y之后,后面就会输出”Thread has ended!”.

你能够在调用Join方法的时候给它一个timeout的參数,比如要超过1秒.

   t.Join(1000);
t.Join(TimeSpan.FromSeconds(1));

2 : 为线程传递參数

为线程传递參数的最简单的方法莫过于运行一个lambda表达式,然后在方法里面给參数了,比如:

        static void Main(string[] args)
{
Thread t = new Thread(()=>Print("hello ,world !"));
t.Start();
Console.ReadKey();
}
static void Print(string message)
{
Console.WriteLine(message);
}

使用这样的方法,你能够传递不论什么參数.

当然Thread的构造函数中有一个传递參数的版本号,你也能够使用以下的代码来传递參数:

 static void Main()
{
Thread t = new Thread(Print);
t.Start("Hello from t!");
} static void Print(object messageObj)
{
string message = (string)messageObj;
Console.WriteLine(message);
}

分析:这里有一点须要注意,由于Print的方法签名必须匹配ParameterrizedThreadStart托付,所以Print的參数必须也是object,所以在Print方法中必须进行强制转换.

3: Lambda和捕获的变量

考虑以下的代码

            for (int i = 0; i < 10; i++)
{
new Thread(() => Console.Write(i)).Start();
}

分析:实际的输出是不确定的,你能够自己试试.

Why?

关键问题是局部变量i在for循环中指向的是相同的内存地址.因此,每一次都在一个执行时会被改变值的变量(i)上调用CW方法,在foreach中也存在相同问题.

解决问题的方法非常easy,比如使用一个暂时变量:

            for (int i = 0; i < 10; i++)
{
int temp = i;
new Thread(() => Console.Write(temp)).Start();
}

由于i是值变量,所以int temp=i会复制i的值给temp,而在for循环中temp变量都是不同的,所以能够解决问题.

以下的也是相同的道理:

            for (int i = 0; i < 10; i++)
{
new Thread((obj) => Console.Write(obj)).Start(i); //由于每个线程的obj都是不同的。
}

以下的案例可能更加明显一点:

            string text = "t1";
Thread t1 = new Thread(() => Console.WriteLine(text));
text = "t2";
Thread t2 = new Thread(() => Console.WriteLine(text)); t1.Start();
t2.Start();

无论你运行几次,貌似都是输出两次t2,为啥呢?

由于两个lambda表达式捕获的是同样的test变量,所以”t2”会被连续打印两次.

4.命名线程

给每个线程一个合适的名字对于调试来说非常有利,尤其是在VS中,由于县城窗体和调试位置工具栏中都会显示线程的名字.

可是你仅仅能设置一次线程的名字,尝试在以后更改名字会抛出一个异常,为变量命名的使用的是Name属性,比如:

            Thread worker = new Thread(Go);
worker.Name = "worker";
worker.Name = "worker";//会抛出异常

5.前台线程和后台线程

默认你显示创建的线程都是前台线程.

仅仅要前台线程有一个还在执行,应用程序就不会结束.

仅仅有全部的前台线程都结束了,应用程序才会结束.

在应用程序结束的时候,全部后台线程都会被终止.

你能够通过现成的IsBackground属性莱产讯和更改现成的状态.

案例:

            if (args.Length>0)
{
worker.IsBackground = true;
}
worker.Start();

假设args.Length>0,则worker就是后台线程,那么应用程序会马上终止.

否则worker默认就是前台线程,所以仅仅有在CR()方法结束后,应用程序才会终止.

所以当你有时候发现关闭了应用程序窗体,可是在任务管理器中应用程序仍然在执行,非常有可能是另一些前台线程在执行.

6.线程的优先级

enum ThreadPriority
{
Lowest,
BelowNormal,
Normal,
AboveNormal,
Highest
}

仅仅有在多个线程的环境中,线程优先级才实用.

把一个现成的优先级提高并不会提高实时系统的性能,由于进程的优先级才是应用程序的瓶颈.为了更好的实时工作,你必须提高进程的优先级.

比如:

process.PriorityClass=ProcessPriorityClass.High.

7.异常捕获

尝试在一个线程中捕获还有一个线程的异常是失败的.案例:

public static void Main()
{
try
{
new Thread(Go).Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); //永远执行不到这里.
}
} static void Go() { throw null;}

我们再还有一个线程中抛出了异常(throw null),然后尝试在主线程中捕获它,我们永远都不会捕获到这个异常.

为了在还有一个线程中捕获异常,必须在那个线程上try,catch,finally.

所以我们能够这么做:

public static void Main()
{
new Thread(Go).Start();
} static void Go()
{
try
{
throw null;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

8.全局捕获异常

Application.DispatcherUnhandledException 事件和Application.ThreadException 事件都仅仅有在主UI线程中抛出异常的时候才会被触发。

为了捕获全部的未处理的异常,你能够使用AppDomain.CurrentDomain.UnhandledException,尽管这个事件在不论什么未处理异常抛出的时候都会被触发。可是它不能让你阻止应用程序的关闭。

关于Thread的那些事的更多相关文章

  1. 说说Thread.Sleep(0)的那些奇怪的事

    写在前面 最近在弄一个传输组件,用到很多多线程的知识,其中有个问题,困扰我很久,不知道是什么原因,脑子一热,在传输过程中,添加了一句代码Thread.Sleep(0).那个问题竟然解决了,耗费我一上午 ...

  2. Java Thread 那些事

    这篇文章被压在草稿箱许久,最近公司内部的技术社区有同学贴出了几篇分享 Java线程的文章,发觉有很多概念没有讲清楚,所以花点时间继续撰写,便有了这篇博文. 本文只聚焦 JVM 层面的线程模型,不考虑和 ...

  3. 4.构造Thread对象你也许不知道的几件事

    1.Thread类对象只有在调用了start()方法之后,JVM虚拟机才会给我们创建一个真正的线程!否则就不能说是创建了线程!也就是说new Thread()之后,此时实际上在计算机底层,操作系统实际 ...

  4. java线程基础巩固---构造Thread对象你也许不知道的几件事

    关于Thread的构造在JDK文档中如下: 之后会把上面所有的构造都会学习到,这次主要是去研究一下图上标红的默认构造,当然大家肯定对于它都有些不屑,这有啥可学的,不new一个然后start线程不就启动 ...

  5. Android笔记——Handler Runnable与Thread的区别

    在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run() ...

  6. 深入理解Thread.sleep的含义

    转载一篇对sleep说的非常好的一篇文章,原文http://www.cnblogs.com/ILove/archive/2008/04/07/1140419.html 我们可能经常会用到 Thread ...

  7. 漫谈c++11 Thread库之使写多线程程序

    c++11中最重要的特性之一就是对多线程的支持了,然而<c++ primer>5th却没有这部分内容的介绍,着实人有点遗憾.在网上了解到了一些关于thread库的内容.这是几个比较不错的学 ...

  8. org.hibernate.HibernateException: No Session found for current thread

    spring.springmvc和hibernate整合 在sessionFactory.getCurrentSession()时,出现以下异常 No Session found for curren ...

  9. Python爬虫爬取糗事百科段子内容

    参照网上的教程再做修改,抓取糗事百科段子(去除图片),详情见下面源码: #coding=utf-8#!/usr/bin/pythonimport urllibimport urllib2import ...

随机推荐

  1. [BZOJ 3884][欧拉定理]上帝与集合的正确使用方法

    看看我们机房某畸形写的题解:http://blog.csdn.net/sinat_27410769/article/details/46754209 此题为popoQQQ神犇所出,在此orz #inc ...

  2. C# Keywords - as

    记录一下在日常开发过程中遇到的一些C# 基础编程的知识! 希望以后能用的着.知识是在平常的开发过程中去学到的.只有用到了,你才能深入的理解它,并用好它. 本资料来源于:MSND 下面是一些相关的cod ...

  3. ros中文术语表及消息类型表

    前言:整理一些ros常用表格,包括中文术语对照表. 一.中文术语表 二.消息类型表 -END-

  4. Spark SQL 编程API入门系列之SparkSQL的依赖

    不多说,直接上干货! 不带Hive支持 <dependency> <groupId>org.apache.spark</groupId> <artifactI ...

  5. Swagger 隐藏具体API

    一.why 在swagger ui界面中有时候不想显示某些api,通过下面的方式可以实现. 1.1.新建一个类实现IDocumentFilter接口 using Swashbuckle.Swagger ...

  6. .NET中的异步操作及线程同步

    执行异步操作 CLR使用了WIN的线程处理能力,但保留了与其分离的权利.某些时候CLR的线程与Win的线程不是完全的匹配. 线程的系统开销较大,应限制其数量. 创建:分配并初始化一线程内核对象,保留1 ...

  7. USB接口

     总结: 1.电脑的usb接口是usb母接口,u盘接口是usb公接口 2.usb otg指的是不需要电脑作为中转站接口,例如如果买一个micro 转otg接口即可将手机直接接u盘 3.方形usb口是u ...

  8. 【转】javascript 小数乘法结果错误处理

    一.用js计算 12.32 * 7  结果是多少? 答案:86.24000000000001   为什么会出现这种问题?怎么解决? js在处理小数的乘除法的时候有一个bug,解决的方法可以是:将小数变 ...

  9. ZBrush中遮罩的概念及使用

    刚接触设计软件的小伙伴有可能不知道什么叫做遮罩,遮罩的概念是什么,顾名思义,遮罩就是可以将局部进行遮挡,使用它可以锁定和保护我们不想改变的模型位置,即被遮罩的部分将不参与任何编辑. ZBrush®软件 ...

  10. k8s集群启动了上万个容器(一个pod里放上百个容器,起百个pod就模拟出上万个容器)服务器超时,无法操作的解决办法

    问题说明: 一个POD里放了百个容器,然后让K8S集群部署上百个POD,得到可运行上万个容器的实验目的. 实验环境:3台DELL裸机服务器,16核+64G,硬盘容量忽略吧,上T了,肯定够. 1.一开始 ...