C# 之多线程(二)
一、确定多线程的结束时间,thread的IsAlive属性
在多个线程运行的背景下,了解线程什么时候结束,什么时候停止是很有必要的。
案例:老和尚念经计时,2本经书,2个和尚念,一人一本,不能撕破,最短时间念完,问老和尚们念完经书最短需要多长时间。
分析:首先在开始念经的时候给计时,记为A,最后在记下慢和尚念完经书时的时间,记为B。求B-A
代码:IsAlive属性:标识此线程已启动并且尚未正常终止或中止,则为 true,再念,没念完,努力中;否则为 false,念完啦,歇着。
//和尚1,和尚2
public Thread td1, td2; public void StarThread()
{
//开启一个线程执行Hello方法,即和尚1念菠萝菠萝蜜
ThreadStart ts = new ThreadStart(Hello);
td1 = new Thread(ts);
td1.Start();
}
public void StarThread1()
{
//开启一个线程执行Welcome方法,即和尚2念大金刚经
ThreadStart ts = new ThreadStart(Welcome);
td2 = new Thread(ts);
td2.Start();
}
public string sayh="", sayw=""; //菠萝菠萝蜜
public void Hello()
{
//念
sayh = "Hellow everyone ! ";
} //大金刚经
public void Welcome()
{
//念
sayw = "Welcome to ShangHai ! ";
//偷懒10秒
Thread.Sleep();
} protected void btn_StarThread_Click(object sender, EventArgs e)
{
//记时开始,预备念
Response.Write("开始念的时间: "+DateTime.Now.ToString() + "</br>");
//和尚1就位
StarThread();
//和尚2就位
StarThread1(); int i = ;
while (i == )
{
//判断线程的IsAlive属性
//IsAlive标识此线程已启动并且尚未正常终止或中止,则为 true;否则为 false。
//如果两个都为false说明,线程结束终止
if (!td1.IsAlive && !td2.IsAlive)
{
i++;
if (i == )
{
//念得内容,绕梁三尺。
Response.Write("我们年的内容: "+(sayh + " + " + sayw) + "</br>");
Response.Write("念完时的时间: "+DateTime.Now.ToString());
Response.End();
}
}
}
}
二、线程优先级,thread的ThreadPriority属性
线程优先级区别于线程占有cpu时间的多少,当然优先级越高同等条件下占有的cpu时间越多。级别高的执行效率要高于级别低的。
优先级有5个级别:Lowest<BelowNormal<Normal<AboveNormal<Highest;默认为Normal。
案例:老和尚娶媳妇。佛祖说:你们3个和尚,清修刻苦,现特许你们娶媳妇啦,不过娶媳妇的只能是你们三个中间的一人。条件是我手中的经书谁能先念完,谁可以娶。
分析:和尚平时都很刻苦,各有特点,平时和尚1在lowest环境下念经,和尚2在normal环境下念经,和尚3在Highest环境下念经。
protected void btn_StarThread_Click(object sender, EventArgs e)
{
Write();
} //i为和尚1念的页数
//j为和尚2念的页数
//k为和尚3念的页数
//c为经书总页数
int i=,j=,k=,c=; //和尚1念经
public void Jsi()
{
while (i <= c)
{
i+=;
}
}
//和尚2念经
public void Jsj()
{
while (j <= c)
{
j+=;
}
}
//和尚3念经
public void Jsk()
{
while (k <= c)
{
k+=;
}
}
public void Write()
{
//开启线程计算i
ThreadStart sti = new ThreadStart(Jsi);
Thread tdi = new Thread(sti);
//设置线程优先级为Lowest。和尚1在Lowest环境下念经
tdi.Priority = ThreadPriority.Lowest; //开启线程计算j
ThreadStart stj = new ThreadStart(Jsj);
Thread tdj = new Thread(stj);
//设置线程优先级为Normal。和尚2在Normal环境下念经
tdj.Priority = ThreadPriority.Normal; //开启线程计算k
ThreadStart stk = new ThreadStart(Jsk);
Thread tdk = new Thread(stk);
//设置线程优先级为Highest。和尚3在Highest环境下念经
tdk.Priority = ThreadPriority.Highest; //开始
tdj.Start();
tdk.Start();
tdi.Start();
int s = ;
while (s==)
{
if (k > c)
{
s++;
Response.Write("比赛结束,结果如下:</br></br>");
Response.Write("和尚1在Lowest环境下念经:" + i + "页</br>和尚2在Normal环境下念经:" + j + "页</br>和尚3在Highest环境下念经:" + k + "页</br></br>");
Response.Write("佛祖又说:你念或者不念,苍老师,就在那里!");
Response.End();
}
}
} 注意:Lowest优先级可能会出现执行快于normal优先级的情况。
三、线程通信之Monitor类
如果,你的线程A中运行锁内方法时候,需要去访问一个暂不可用资源B,可能在B上需耗费很长的等待时间,那么这时候你的线程A,将占用锁内资源,阻塞其它线程访问锁定内容,造成性能损失。你该怎么解决这样子的问题呢?这样,让A暂时放弃锁,停留在锁中的,允许其它线程访问锁,而等B资源可用时,通知A让他继续锁内的操作。是不是解决啦问题,这样就用到啦这段中的Monitor类,提供的几个方法:Wait(),Pulse(),PulseAll(),这几个方法只能在当前锁定中使用。
Wait():暂时中断运行锁定中线程操作,释放锁,时刻等待着通知复活。
Pulse():通知等待该锁线程队列中的第一个线程,此锁可用。
PulseAll():通知所有锁,此锁可用。
案例:嵩山少林和尚开会。主持人和尚主持会议会不停的上舞台讲话,方丈会出来宣布大会开始,弟子们开始讨论峨眉山怎么走。
分析:主持人一个线程,方丈一个线程,弟子们一个线程,主持人贯彻全场。
public class MutexSample
{
static void Main()
{
comm com = new comm();
com.dhThreads();
Console.ReadKey();
}
}
public class comm
{
//状态值:0时主持人和尚说,1时方丈说,2时弟子们说,3结束。
int sayFla;
//主持人上台
int i = ;
public void zcrSay()
{
lock (this)
{
string sayStr;
if (i == )
{
//让方丈说话
sayFla = ;
sayStr = Thread.CurrentThread.Name+"今晚,阳光明媚,多云转晴,方丈大师,程祥云而来,传扬峨眉一隅,情况如何,还请方丈闪亮登场。";
Console.WriteLine(sayStr);
i++;
//此时sayFla=1通知等待的方丈线程运行
Monitor.Pulse(this);
//暂时锁定主持人,暂停到这里,释放this让其它线程访问
Monitor.Wait(this); }
//被通知后,从上一个锁定开始运行到这里
if (i == )
{
//让弟子说话
sayFla = ;
sayStr = Thread.CurrentThread.Name + "看方丈那幸福的表情,徜徉肆恣,愿走的跟他去吧。下面请弟子们各抒己见";
Console.WriteLine(sayStr);
i++;
//此时sayFla=12通知等待的弟子线程运行
Monitor.Pulse(this);
//暂时锁定主持人,暂停到这里,释放this让其它线程访问
Monitor.Wait(this);
}
//被通知后,从上一个锁定开始运行到这里
if (i == )
{
sayFla = ;
sayStr = Thread.CurrentThread.Name + "大会结束!方丈幸福!!苍老师你在哪里?!!放开那女孩 ...";
Console.WriteLine(sayStr);
i++;
Monitor.Wait(this);
}
}
}
//方丈上台
public void fzSay()
{
lock (this)
{
while (true)
{
if (sayFla != )
{
Monitor.Wait(this);
}
if (sayFla == )
{
Console.WriteLine(Thread.CurrentThread.Name + "蓝蓝的天空,绿绿的湖水,我看见,咿呀呀呀,看见一老尼,咿呀呀,在水一方。愿意来的一起来,不愿来的苍老师给你们放寺里。。咿呀呀,我走啦。。。");
//交给主持人
sayFla = ;
//通知主持人线程,this可用
Monitor.Pulse(this);
}
}
}
}
//弟子上台
public void dzSay()
{
lock (this)
{
while (true)
{
if (sayFla != )
{
Monitor.Wait(this);
}
if (sayFla == )
{
Console.WriteLine(Thread.CurrentThread.Name + "果真如此的话,还是方丈大师自己去吧!! 祝福啊 .... ");
//交给主持人
sayFla = ;
Monitor.Pulse(this);
}
} }
}
public void dhThreads()
{
Thread zcrTd = new Thread(new ThreadStart(zcrSay));
Thread fzTd = new Thread(new ThreadStart(fzSay));
Thread dzTd = new Thread(new ThreadStart(dzSay));
zcrTd.Name = "主持人:";
fzTd.Name = "方丈:";
dzTd.Name = "弟子:";
zcrTd.Start();
fzTd.Start();
dzTd.Start();
}
}
四、线程排队之Join
多线程,共享一个资源,先后操作资源。Join()方法,暂停当前线程,直到指定线程运行完毕,才唤醒当前线程。如果没有Join,多线程随机读取公用资源,没有先后次序。
案例:两个和尚念一本经书,老和尚年前半本书,小和尚念后半本书,小和尚调皮,非要先念,就给老和尚用迷魂药啦。。
分析:一本书6页,小和尚4-6,老和尚1-3,两个和尚,两个线程。
public class 连接线程Join
{
//小和尚
public static Thread litThread;
//老和尚
public static Thread oldThread; //老和尚念经
static void oldRead()
{
//老和尚被小和尚下药
litThread.Join(); //暂停oldThread线程,开始litThread,直到litThread线程结束,oldThread才继续运行,如果不适用Join将小和尚一句,老和尚一句,随即没有规则的。
for (int i = ; i <= ; i++)
{
Console.WriteLine(i);
}
}
//小和尚念经
static void litRead()
{
for (int i = ; i <= ; i++)
{
Console.WriteLine(i);
}
}
static void Main(string[] args)
{
oldThread = new Thread(new ThreadStart(oldRead));
litThread = new Thread(new ThreadStart(litRead)); oldThread.Start();
// FristThread.Join(); //暂停oldThread线程,开始litThread,直到litThread线程结束,oldThread才继续运行
litThread.Start();
Console.ReadKey();
}
}
五、多线程互斥锁Mutex
互斥锁是一个同步的互斥对象,适用于,一个共享资源,同时只能有一个线程能够使用。
共享资源加互斥锁,需要两部走:1.WaitOne(),他将处于等待状态知道可以获取资源上的互斥锁,获取到后,阻塞主线程运行,直到释放互斥锁结束。2.ReleaseMutex(),释放互斥锁,是其它线程可以获取该互斥锁。
案例:和尚写日记。最近寺庙香火不旺,为啦节约用水,方丈发话两个和尚用一个本子写日记。
分析:好比多个线程写日志,同时只能有一个线程写入日志文件。
public class 多线程互斥锁Mutex
{
static void Main(string[] args)
{
IncThread ict = new IncThread("大和尚", );
DecThread dct = new DecThread("小和尚", );
Console.ReadKey();
}
}
class SharedRes
{
public static int count = ;
//初始化互斥锁,没被获取
public static Mutex mtx = new Mutex();
////初始化互斥锁,被主调线程获取
//public static Mutex mtx = new Mutex(true);
} class IncThread
{
int num;
public Thread thrd;
public IncThread(string name ,int n)
{
thrd = new Thread(new ThreadStart(this.run));
thrd.Name = name;
num = n;
thrd.Start();
}
//写日记,过程
void run()
{
Console.WriteLine(thrd.Name + " , 等待互斥锁 。");
SharedRes.mtx.WaitOne();
Console.WriteLine(thrd.Name + " ,获得互斥锁 。");
do
{
Thread.Sleep();
SharedRes.count++;
Console.WriteLine("今天我 " + thrd.Name + " 比较强,这样写吧 :" + SharedRes.count);
num--;
}while(num>);
Console.WriteLine(thrd.Name + " , 释放互斥锁 。");
SharedRes.mtx.ReleaseMutex();
}
}
class DecThread
{
int num;
public Thread thrd; public DecThread(string name, int n)
{
thrd = new Thread(new ThreadStart(this.run));
thrd.Name = name;
num = n;
thrd.Start();
}
//写日记,过程
void run()
{
Console.WriteLine(thrd.Name + ", 等待互斥锁 。");
SharedRes.mtx.WaitOne();
Console.WriteLine(thrd.Name + " ,获得互斥锁 。");
do
{
Thread.Sleep();
SharedRes.count--;
Console.WriteLine("今天我 " + thrd.Name + " 比较衰,这样写吧 :" + SharedRes.count);
num--;
} while (num > );
Console.WriteLine(thrd.Name + " , 释放互斥锁 。");
SharedRes.mtx.ReleaseMutex();
}
}
六、信号量semaphore
类似于互斥锁,只不过他可以指定多个线程来访问,共享资源。在初始化信号量的同时,指定多少个线程可以访问,假如允许2个线程访问,而却有3个线程等待访问,那么他将只允许2个访问,一旦已访问的2个线程中有一个访问完成释放信号量,那么没有访问的线程立马可以进入访问。
案例:和尚抓鸡,3个和尚抓鸡,只有两只鸡,那么鸡圈管理员只允许2个和尚先进,抓到说三句话放下,出来,让第三个和尚进去抓。
分析:三个线程,初始信号量允许2个线程访问。
public class 信号量semaphore
{
static void Main(string[] args)
{
MyThread td1 = new MyThread("降龙");
MyThread td2 = new MyThread("伏虎");
MyThread td3 = new MyThread("如来");
td1.td.Start();
td2.td.Start();
td3.td.Start();
Console.ReadKey();
}
} public class MyThread
{
//初始化,新号量,允许2个线程访问,最大2也是2个。
public static Semaphore sem = new Semaphore(,);
public Thread td;
public MyThread(string name)
{
td = new Thread(new ThreadStart(this.Run));
td.Name = name;
}
//过程很美好
public void Run()
{
Console.WriteLine(td.Name+",等待一个信号量。");
sem.WaitOne();
Console.WriteLine(td.Name+",已经获得新号量。");
Thread.Sleep();
//很有深意的三句话
char[] cr = { 'a','o','e'};
foreach (char v in cr)
{
Console.WriteLine(td.Name+",输出v: "+v);
Thread.Sleep();
}
Console.WriteLine(td.Name+",释放新号量。");
sem.Release();
}
}
结束,笑纳,海涵。
C# 之多线程(二)的更多相关文章
- java 多线程二
java 多线程一 java 多线程二 java 多线程三 java 多线程四 线程中断: /** * Created by root on 17-9-30. */ public class Test ...
- java基础-多线程二
java基础-多线程二 继承thread和实现Runnable的多线程每次都需要经历创建和销毁的过程,频繁的创建和销毁大大影响效率,线程池的诞生就可以很好的解决这一个问题,线程池可以充分的利用线程进行 ...
- C#夯实基础之多线程二:主线程、前台线程与后台线程
我们在<C#夯实基础之多线程一:初识多线程>一文中第二部分中指出,既然windows最终发展出了多线程模型,按理说,我们直接使用一个.NetFramework的线程类就可以直接撸代码了,但 ...
- Java:多线程<二> 同步
由于多线程的访问出现延迟和线程的随机性,在使用多线程时往往会伴随安全性的问题,这些问题一旦出现将会是非常严重的.为了解决这种安全性问题,synchronized出现了. synchronized用法一 ...
- Java多线程——<二>将任务交给线程,线程声明及启动
一.任务和线程 <thinking in java>中专门有一小节中对线程和任务两个概念进行了具体的区分,这也恰好说明任务和线程是有区别的. 正如前文所提到的,任务只是一段代码,一段要达成 ...
- 从零开始学习Java多线程(二)
前面已经简单介绍进程和线程,为后续学习做铺垫.本文讨论多线程传参,Java多线程异常处理机制. 1. 多线程的参数传递 在传统开发过程中,我们习惯在调用函数时,将所需的参数传入其中,通过函数内部逻辑处 ...
- 多线程二:线程池(ThreadPool)
在上一篇中我们讲解了多线程的一些基本概念,并举了一些例子,在本章中我们将会讲解线程池:ThreadPool. 在开始讲解ThreadPool之前,我们先用下面的例子来回顾一下以前讲过的Thread. ...
- Java多线程(二) —— 深入剖析ThreadLocal
对Java多线程中的ThreadLocal类还不是很了解,所以在此总结一下. 主要参考了http://www.cnblogs.com/dolphin0520/p/3920407.html 中的文章. ...
- python多线程(二)
原文:http://blog.sina.com.cn/s/blog_4b5039210100esc1.html 基础不必多讲,还是直接进入python. Python代码代码的执行由python虚拟机 ...
- 并发和多线程(二)--线程安全、synchronized、CAS简介
线程安全性: 当多个线程访问一个类的时候,这个类始终表示出正确的行为,那么这个类是线程安全的. 无状态的对象一定是线程安全的,例如大部分service.dao.Servlet都是无状态的. 线程安全体 ...
随机推荐
- B - 영어(字符串)
原题链接 B - 영어 Time Limit:1000MS Memory Limit:131072KB 64bit IO Format:%lld & %llu Submit S ...
- 腾讯云服务器部署 django项目整个流程
CentOS7下部署Django项目详细操作步骤 前记:购买腾讯云服务器,配置自选,当然新用户免费体验半个月,我选择的系统是centos7系统版本, 接下来我们来看整个配置项目流程. 部署是基于:ce ...
- php扩展编译流程路
- 【vue】——vue.js 获取当前 自定义属性值
假设有一个标签h5, 我们给它添加了一个自定义属性值,(item.id是从动态添加的) 点击h5 标签,如何才能获取当前对应的自定义属性值呢? 想当然的我最开始这样写: <h5 class=&q ...
- [Swift]数组排序:sort和sorted
sorted只返回一个数组的有序版本,不修改原数组. sort无返回值,只会修改原数组. 定义一个需要排序的数组,其包含元素.示例只初始化一个Int数组. var arr:[Int] = [Int]( ...
- VMware Workstation 14 pro License Keys
AC5XK-0ZD4H-088HP-9NQZV-ZG2R4 CG54H-D8D0H-H8DHY-C6X7X-N2KG6 ZC3WK-AFXEK-488JP-A7MQX-XL8YF ZC5XK-A6E0 ...
- scrapy之 downloader middleware
一. 功能说明 Downloader Middleware有三个核心的方法 process_request(request, spider) process_response(request, res ...
- KMP算法再解 (看毛片算法真是人如其名,哦不,法如其名。)
KMP算法主要解决字符串匹配问题,其中失配数组next很关键: 看毛片算法真是人如其名,哦不,法如其名. 看了这篇博客,转载过来看一波: 原博客地址:https://blog.csdn.net/sta ...
- L05-Linux部署msmtp+mutt发送邮件
一.前言 首先,得明白发送一封邮件的流程,下面一段理论摘抄自廖雪峰的官网网站https://www.liaoxuefeng.com/article/00137387674890099a71c04005 ...
- 【算法笔记】A1039 Course List for Student
https://pintia.cn/problem-sets/994805342720868352/problems/994805447855292416 题意: 有N个学生,K节课.给出选择每门课的 ...