C#多线程编程实战(一):线程基础
1.1 简介
为了防止一个应用程序控制CPU而导致其他应用程序和操作系统本身永远被挂起这一可能情况,操作系统不得不使用某种方式将物理计算分割为一些虚拟的进程,并给予每个执行程序一定量的计算能力。此外操作系统必须始终能够优先访问CPU,并能调整不同程序访问CPU的优先级。线程正式这一慨念的实现。
多线程优点:可以同时执行多个计算任务,有可能提高计算机的处理能力,使得计算机每秒能执行越来越多的命令
多线程缺点:消耗大量的操作系统资源。多个线程共享一个处理器将导致操作系统忙于管理这些线程,而无法运行程序。
1.2 创建线程
using System;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{ Thread t1 = new Thread(new ThreadStart(PrintNumbers));//无参数的委托
t1.Start(); Thread t2 = new Thread(new ParameterizedThreadStart(PrintNumbers));//有参数的委托
t2.Start();
Console.ReadLine();
} static void PrintNumbers()
{
Console.WriteLine("Starting...");
for (int i = ; i < ; i++)
{
Console.WriteLine(i);
}
} //注意:要使用ParameterizedThreadStart,定义的参数必须为object
static void PrintNumbers(object count)
{
Console.WriteLine("Starting...");
for (int i = ; i < Convert.ToInt32(count); i++)
{
Console.WriteLine(i);
}
}
}
}
注释:我们只需指定在不同线程运行的方法名,而C#编译器会在后台创建这些对象
1.3 暂停线程
using System;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{ Thread t1 = new Thread(PrintNumbersWithDelay);
t1.Start();
PrintNumbers();
Console.ReadLine();
} static void PrintNumbers()
{
Console.WriteLine("Starting...");
for (int i = ; i < ; i++)
{ Console.WriteLine(i);
}
} static void PrintNumbersWithDelay()
{
Console.WriteLine("Starting...");
for (int i = ; i < ; i++)
{
Thread.Sleep(TimeSpan.FromSeconds());
Console.WriteLine(i);
}
}
}
}
注释:使用Thread.Sleep(TimeSpan.FromSeconds(2));暂停线程
1.4 线程等待
using System;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting...");
Thread t = new Thread(PrintNumbersWithDelay);
t.Start();
t.Join(); //使用Join等待t完成
PrintNumbers();
Console.WriteLine("THread Complete");
Console.ReadLine();
} static void PrintNumbers()
{
Console.WriteLine("Starting...");
for (int i = ; i < ; i++)
{ Console.WriteLine(i);
}
} static void PrintNumbersWithDelay()
{
Console.WriteLine("Starting...");
for (int i = ; i < ; i++)
{
Thread.Sleep(TimeSpan.FromSeconds());
Console.WriteLine(i);
}
}
}
}
注释:使用t.Join(); 等待t完成
1.5 终止线程
using System;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting Program...");
Thread t1 = new Thread(PrintNumbersWithDelay);
t1.Start();
Thread.Sleep(TimeSpan.FromSeconds());
t1.Abort(); //使用Abort()终止线程
Console.WriteLine("Thread t1 has been aborted");
Thread t2 = new Thread(PrintNumbers);
PrintNumbers();
Console.ReadLine();
} static void PrintNumbers()
{
Console.WriteLine("Starting...");
for (int i = ; i < ; i++)
{ Console.WriteLine(i);
}
} static void PrintNumbersWithDelay()
{
Console.WriteLine("Starting...");
for (int i = ; i < ; i++)
{
Thread.Sleep(TimeSpan.FromSeconds());
Console.WriteLine(i);
}
}
}
}
注释:使用Thread实例的Abort方法终止线程
1.6 检测线程状态
using System;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Start Program...");
Thread t1 = new Thread(PrintNumbersWithStatus);
Thread t2 = new Thread(DoNothing);
Console.WriteLine(t1.ThreadState.ToString());//获取实例线程状态
t2.Start();
t1.Start();
for (int i = ; i < ; i++)
{
Console.WriteLine(t1.ThreadState.ToString());
}
Thread.Sleep(TimeSpan.FromSeconds());
t1.Abort();
Console.WriteLine("thread t1 has been aborted");
Console.WriteLine(t1.ThreadState.ToString());
Console.WriteLine(t2.ThreadState.ToString());
Console.ReadLine();
} private static void PrintNumbersWithStatus()
{
Console.WriteLine("Starting...");
Console.WriteLine(Thread.CurrentThread.ThreadState.ToString());//获取当前线程状态
for (int i = ; i < ; i++)
{
Thread.Sleep(TimeSpan.FromSeconds());
Console.WriteLine(i);
}
} private static void DoNothing()
{
Thread.Sleep(TimeSpan.FromSeconds());
}
}
}
注释:使用Thread.ThreadState获取线程的运行状态。ThreadState是一个C#枚举。谨记:不要在程序中使用线程终止,否则可能会出现意想不到的结果
1.7 线程优先级
using System;
using System.Diagnostics;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"Current thread priority: {Thread.CurrentThread.Priority}");
Console.WriteLine("Running on all cores available");//获取实例线程状态
RunThreads(); Thread.Sleep(TimeSpan.FromSeconds());
Console.WriteLine("Running on a single Core");
//让操作系统的所有线程运行在单个CPU核心上
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr();
RunThreads();
Console.ReadLine();
} private static void RunThreads()
{
var sample = new ThreadSample(); var t1 = new Thread(sample.CountNumbers);
t1.Name = "Thread One";
var t2 = new Thread(sample.CountNumbers);
t2.Name = "Thread Two"; t1.Priority = ThreadPriority.Highest;//使用Priority设置线程的优先级
t2.Priority = ThreadPriority.Lowest;
t1.Start();
t2.Start(); Thread.Sleep(TimeSpan.FromSeconds());
sample.Stop();
}
} class ThreadSample
{
private bool _isStopped = false;
public void Stop()
{
_isStopped = true;
} public void CountNumbers()
{
long counter = ;
while (!_isStopped)
{
counter++;
}
Console.WriteLine($"{Thread.CurrentThread.Name} with {Thread.CurrentThread.Priority} priority has a count={counter.ToString("N0")}");
}
}
}
注释:单核执行多线程耗费的时间比多核的多很多
1.8 前台线程和后台线程
using System;
using System.Diagnostics;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{
var sampleForground = new ThreadSample();
var sampleBackground = new ThreadSample();
var t1 = new Thread(sampleForground.CountNumbers);
t1.Name = "ForegroundThread"; //没有明确声明的均为前台线程
var t2 = new Thread(sampleBackground.CountNumbers);
t2.Name = "BackgroundThread";
t2.IsBackground = true; //设置为后台线程 t1.Start();
t2.Start();
}
} class ThreadSample
{
private readonly int _iteration; public ThreadSample(int iteration)
{
_iteration = iteration;
} public void CountNumbers()
{
for (int i = ; i < _iteration; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
}
}
}
}
注释:进程会等待所有的前台线程完成后再结束工作,但是如果只剩下后台线程,则会直接结束工作
1.9 向线程传递参数
using System;
using System.Diagnostics;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{
ThreadSample sample = new ThreadSample(); Thread t1 = new Thread(sample.CountNumbers);
t1.Name = "ThreadOne";
t1.Start();
t1.Join();
Console.WriteLine("--------------------------"); Thread t2 = new Thread(Count);
t2.Name = "ThreadTwo";
t2.Start();
t2.Join();
Console.WriteLine("--------------------------"); //使用lambda表达式引用另一个C#对方的方式被称为闭包。当在lambda表达式中使用任何局部变量时,C#会生成一个类,并将该变量作为该类的一个属性,但是我们无须定义该类,C#编译器会自动帮我们实现
Thread t3 = new Thread(()=> CountNumbers());
t3.Name = "ThreadThree";
t3.Start();
t3.Join();
Console.WriteLine("--------------------------"); int i = ;
Thread t4 = new Thread(() => PrintNumber(i)); i = ;
Thread t5 = new Thread(() => PrintNumber(i));
t4.Start();
t5.Start();
//t4, t5都会输出20, 因为t4,t5没有Start之前i已经变成20了
Console.ReadKey();
} static void Count(object iterations)
{
CountNumbers((int)iterations);
} static void CountNumbers(int iterations)
{
for (int i = ; i <= iterations; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
}
} static void PrintNumber(int number)
{
Console.WriteLine(number);
}
} class ThreadSample
{
private readonly int _iteration; public ThreadSample(int iteration)
{
_iteration = iteration;
} public void CountNumbers()
{
for (int i = ; i <= _iteration; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
}
}
}
}
注释:也可以使用ThreadStart传递参数
1.10 使用C# lock关键字
using System;
using System.Diagnostics;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Incorrect Counter");
Counter c1 = new Counter();
var t1 = new Thread(() => TestCounter(c1));
var t2 = new Thread(() => TestCounter(c1));
var t3 = new Thread(() => TestCounter(c1));
t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join();
Console.WriteLine($"Total Count: {c1.Count}");
Console.WriteLine("------------------------"); Console.WriteLine("Correct counter");
CounterWithLock c2 = new CounterWithLock();
t1 = new Thread(() => TestCounter(c2));
t2 = new Thread(() => TestCounter(c2));
t3 = new Thread(() => TestCounter(c2));
t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join();
Console.WriteLine($"Total count:{c2.Count}");
Console.ReadLine();
} static void TestCounter(CounterBase c)
{
for (int i = ; i < ; i++)
{
c.Increment();
c.Decrement();
}
} class Counter : CounterBase
{
public int Count { get; private set; }
public override void Decrement()
{
Count--;
} public override void Increment()
{
Count++;
}
} class CounterWithLock : CounterBase
{
private readonly object _asyncRoot = new object();
public int Count { get; private set; }
public override void Decrement()
{
lock (_asyncRoot)
{
Count--;
}
} public override void Increment()
{
lock (_asyncRoot)
{
Count++;
}
}
} abstract class CounterBase
{
public abstract void Increment(); public abstract void Decrement();
}
} class ThreadSample
{
private readonly int _iteration; public ThreadSample(int iteration)
{
_iteration = iteration;
} public void CountNumbers()
{
for (int i = ; i <= _iteration; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
}
}
}
}
注释:不加锁,得出的结果不确定,竞争条件下很容易出错。加锁得出的结果是正确的,但是性能受到了影响
1.11 使用Monitor类锁定资源
using System;
using System.Diagnostics;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{
object lock1 = new object();
object lock2 = new object();
new Thread(() => LockTooMuch(lock1, lock2)).Start();
lock (lock2)
{
Thread.Sleep();
Console.WriteLine("Monitor.TryEnter allows not to get stuck, returning false after a specified timeout is elapsed");
//直接使用Monitor.TryEnter, 如果在第二个参数之前还未获取到lock保护的资源会返回false
if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds()))
{
Console.WriteLine("Acquired a protected resource successfully");
}
else
{
Console.WriteLine("Timeout acquiring a resource");
}
}
new Thread(() => LockTooMuch(lock1, lock2)).Start();
Console.WriteLine("-----------------------------");
/* 下面代码会造成死锁, 所以注释掉
lock (lock2)
{
Console.WriteLine("This will be a deadlock!");
Thread.Sleep(1000);
lock (lock1)
{
Console.WriteLine("Acquired a protected resource successfully");
}
}
*/
} static void LockTooMuch(object lock1, object lock2)
{
lock (lock1)
{
Thread.Sleep();
lock (lock2);
}
}
}
}
注释:Monitor.TryEnter在指定的时间内尝试获取指定对象上的排他锁
1.12 处理异常
using System;
using System.Diagnostics;
using System.Threading; namespace MulityThreadNote
{
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(FaultyThread);
t.Start();
t.Join();
try
{
t = new Thread(BadFaultyThread);
t.Start();
}
catch (Exception ex)
{
Console.WriteLine("We won't get here");
}
}
static void BadFaultyThread()
{
Console.WriteLine("Starting a faulty thread.....");
Thread.Sleep(TimeSpan.FromSeconds());
//这个异常主线程无法捕捉到,因为是在子线程抛出的异常。需要在子线程中加入try...catch捕获异常
throw new Exception("Boom!");
}
static void FaultyThread()
{
try
{
Console.WriteLine("Starting a faulty thread...");
Thread.Sleep(TimeSpan.FromSeconds());
throw new Exception("Boom");
}
catch (Exception ex)
{
Console.WriteLine($"Exception handled: {ex.Message}");
}
}
}
}
注释:
C#多线程编程实战(一):线程基础的更多相关文章
- Java多线程编程实战指南(核心篇)读书笔记(五)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76730459冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- 《Java多线程编程实战指南(核心篇)》阅读笔记
<Java多线程编程实战指南(核心篇)>阅读笔记 */--> <Java多线程编程实战指南(核心篇)>阅读笔记 Table of Contents 1. 线程概念 1.1 ...
- Java多线程编程实战02:多线程编程模型
多线程编程模型 线程安全名词 串行.并发和并行 串行:一个人,将任务一个一个完成 并发:一个人,有策略地同时做多件事情 并行:多个人,每人做一个事情 竞态 名词 竞态:计算结果的正确性与时间有关的现象 ...
- Java多线程编程实战读书笔记(一)
多线程的基础概念本人在学习多线程的时候发现一本书——java多线程编程实战指南.整理了一下书中的概念制作成了思维导图的形式.按照书中的章节整理,并添加一些个人的理解.
- C#多线程编程实战(二)
1.1 简介 为了防止一个应用程序控制CPU而导致其他应用程序和操作系统本身永远被挂起这一可能情况,操作系统不得不使用某种方式将物理计算分割为一些虚拟的进程,并给予每个执行程序一定量的计算能力.此外操 ...
- Java多线程编程实战指南(核心篇)读书笔记(四)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76690961冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Java多线程编程实战指南(核心篇)读书笔记(三)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76686044冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Java多线程编程实战指南(核心篇)读书笔记(二)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76651408冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Java多线程编程实战指南(核心篇)读书笔记(一)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76422930冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- ASP.Net教程系列:多线程编程实战(一)
Web开发中使用多线程可以增强用户体验,尤其是多用户.多任务.海量数据和资源紧张的情况下.所以我们的ASP.Net教程设立多线程编程实战专题.下面这些代码范例都是入门级的,希望对对大家学习ASP.Ne ...
随机推荐
- codeforces Good bye 2016 E 线段树维护dp区间合并
codeforces Good bye 2016 E 线段树维护dp区间合并 题目大意:给你一个字符串,范围为‘0’~'9',定义一个ugly的串,即串中的子串不能有2016,但是一定要有2017,问 ...
- CF821 C. Okabe and Boxes 栈模拟
Link 题意:给出操作,如果当前出栈操作使得出栈序列非顺序,可以在此之前自由排序栈中所有数,问最少排几次. 思路:已经出栈到第x个元素时,每次需要排序的操作后,能够保证前x元素出栈有序,否则说明该操 ...
- C++类四个默认函数&深复制&浅复制
学习C++语言的同学都知道,C++中类是有默认的几个函数的,主要是有四个函数: 四个函数 默认构造函数:A(void),无参构造函数 拷贝(复制)构造函数:A(const A&a).用一个对象 ...
- .net core 中 identity server 4 之Topic --定义API资源
想要让客户端能够访问API资源,就需要在Identity Server中定义好API的资源. Scope作用域:即API资源的访问范围限制. 作用域是一个资源 (通常也称为 Web API) 的标识符 ...
- MongoDB-3.4集群搭建:分片
概念 集群拥有三个节点: 分片(sharding),分发路由(query routers)和配置服务器 (config server) Shard 分片是存储了一个集合部分数据的MongoDB实例,每 ...
- jQuery插件ASP.NET应用之AjaxUpload
本次使用AJAXUPLOAD做为上传客户端无刷上传插件,其最新版本为3.9,官方地址:http://valums.com/ajax-upload/ 在页面中引入 jquery.min.1.4.2.js ...
- SQL 变量 条件查询 插入数据
(本文只是总结网络上的教程) 在操作数据库时 SQL语句中难免会用到变量 比如 在條件值已知的情況下 INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值 ...
- 19.Remove Nth Node From End of List---双指针
题目链接 题目大意:删除单链表中倒数第n个节点.例子如下: 法一:双指针,fast指针先走n步,然后slow指针与fast一起走,记录slow前一个节点,当fast走到链表结尾,slow所指向的指针就 ...
- 《深入理解Java虚拟机》笔记--第三章 、垃圾收集器与内存分配策略
1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言. Java的垃圾收集(Garbage Collection)主要关注堆和方法区的内存回收. 在GC堆进行回收前,第一件 ...
- 服务器Java环境配置
/* 当要在服务器里搭建Java web项目时, 要先配置好Java需要的环境 */ //jdk [root@localhost ~]# cd /usr/local/src [root@localho ...