关于Thread的那些事

关于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,尽管这个事件在不论什么未处理异常抛出的时候都会被触发。可是它不能让你阻止应用程序的关闭。

时间: 2024-10-17 12:49:16

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

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

写在前面 最近在弄一个传输组件,用到很多多线程的知识,其中有个问题,困扰我很久,不知道是什么原因,脑子一热,在传输过程中,添加了一句代码Thread.Sleep(0).那个问题竟然解决了,耗费我一上午的时间,一点一点的排查是不是代码逻辑有问题.到最后一句话解决了,兴奋归兴奋,但是为什么这句话就能解决我的问题呢?而且还是睡个0,是不是你也遇到过这种情况?不妨一起讨论下这句神奇的代码! Thread.Sleep(0)妙解 这里收集了网上的一篇文章,解释的非常有趣,转载在博客中,也推荐给大家一起看看.

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

1.Thread类对象只有在调用了start()方法之后,JVM虚拟机才会给我们创建一个真正的线程!否则就不能说是创建了线程!也就是说new Thread()之后,此时实际上在计算机底层,操作系统实际上并没有为我们创建线程! 在我们new Thread();的时候,我们点击源码就可以看到: public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); } 实际上是调用了init()方法,而且这个init()方法有

Android开发:Handler Runnable和Thread之间的区别和联系 应用--------------------看完本篇,从此一览无余!

http://blog.csdn.net/yanzi1225627/article/details/8582081 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限. 下面看例子: package org.thread.demo; class MyThread extends

Java中继承thread类与实现Runnable接口的区别

Java中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过实现Runnable接口,实例化Thread类 在实际应用中,我们经常用到多线程,如车站的售票系统,车站的各个售票口相当于各个线程.当我们做这个系统的时候可能会想到两种方式来实现,继承Thread类或实现Runnable接口,现在看一下这两种方式实现的两种结果. Java代码   package com.threadtest; class MyThread e

一步一步掌握线程机制(六)---Atomic变量和Thread局部变量

一步一步掌握线程机制(六)---Atomic变量和Thread局部变量 前面我们已经讲过如何让对象具有Thread安全性,让它们能够在同一时间在两个或以上的Thread中使用.Thread的安全性在多线程设计中非常重要,因为race condition是非常难以重现和修正的,我们很难发现,更加难以改正,除非将这个代码的设计推翻来过. 同步最大的问题不是我们在需要同步的地方没有使用同步,而是在不需要同步的地方使用了同步,导致效率极度低下.所以,我们要想办法限制同步,因为无谓的同步比起无谓的运算还更

【转】Netty那点事(四)Netty与Reactor模式

[原文]https://github.com/code4craft/netty-learning/blob/master/posts/ch4-reactor.md 一:Netty.NIO.多线程? 时隔很久终于又更新了!之前一直迟迟未动也是因为积累不够,后面比较难下手.过年期间@李林锋hw发布了一个Netty5.0架构剖析和源码解读 http://vdisk.weibo.com/s/C9LV9iVqH13rW/1391437855,看完也是收获不少.前面的文章我们分析了Netty的结构,这次咱们

Thread.sleep(0)的作用

我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 假设现在是 2008-4-7 12:00:00.000,如果我调用一下 Thread.Sleep(1000) ,在 2008-4-7 12:00:01.000 的时候,这个线程会 不会被唤醒?某人的代码中用了一句看似莫明其妙的话:Thread.Sleep(0) .既然是 Sleep 0 毫秒,那么他跟去掉这句代码相比,有啥区别么?我们先回顾一下操作系统原理. 操作

【python标准库学习】thread,threading(一)多线程的介绍和使用

在单个程序中我们经常用多线程来处理不同的工作,尤其是有的工作需要等,那么我们会新建一个线程去等然后执行某些操作,当做完事后线程退出被回收.当一个程序运行时,就会有一个进程被系统所创建,同时也会有一个线程运行,这个线程就是主线程main,在主线程中所创建的新的线程都是子线程,子线程通常都是做一些辅助的事.python中提供了thread和threading两个模块来支持多线程. python中使用线程有两种方式,第一种是用thread模块的start_new_thread函数,另一种是用threa

糗事百科python爬虫

# -*- coding: utf-8 -*- #coding=utf-8 import urllib import urllib2 import re import thread import time class QSBK: def __init__(self): self.pageIndex=1 self.user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' self.header={'User-Agent':self.