一、确定多线程的结束时间,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# 之多线程(二)的更多相关文章

  1. java 多线程二

    java 多线程一 java 多线程二 java 多线程三 java 多线程四 线程中断: /** * Created by root on 17-9-30. */ public class Test ...

  2. java基础-多线程二

    java基础-多线程二 继承thread和实现Runnable的多线程每次都需要经历创建和销毁的过程,频繁的创建和销毁大大影响效率,线程池的诞生就可以很好的解决这一个问题,线程池可以充分的利用线程进行 ...

  3. C#夯实基础之多线程二:主线程、前台线程与后台线程

    我们在<C#夯实基础之多线程一:初识多线程>一文中第二部分中指出,既然windows最终发展出了多线程模型,按理说,我们直接使用一个.NetFramework的线程类就可以直接撸代码了,但 ...

  4. Java:多线程<二> 同步

    由于多线程的访问出现延迟和线程的随机性,在使用多线程时往往会伴随安全性的问题,这些问题一旦出现将会是非常严重的.为了解决这种安全性问题,synchronized出现了. synchronized用法一 ...

  5. Java多线程——<二>将任务交给线程,线程声明及启动

    一.任务和线程 <thinking in java>中专门有一小节中对线程和任务两个概念进行了具体的区分,这也恰好说明任务和线程是有区别的. 正如前文所提到的,任务只是一段代码,一段要达成 ...

  6. 从零开始学习Java多线程(二)

    前面已经简单介绍进程和线程,为后续学习做铺垫.本文讨论多线程传参,Java多线程异常处理机制. 1. 多线程的参数传递 在传统开发过程中,我们习惯在调用函数时,将所需的参数传入其中,通过函数内部逻辑处 ...

  7. 多线程二:线程池(ThreadPool)

    在上一篇中我们讲解了多线程的一些基本概念,并举了一些例子,在本章中我们将会讲解线程池:ThreadPool. 在开始讲解ThreadPool之前,我们先用下面的例子来回顾一下以前讲过的Thread. ...

  8. Java多线程(二) —— 深入剖析ThreadLocal

    对Java多线程中的ThreadLocal类还不是很了解,所以在此总结一下. 主要参考了http://www.cnblogs.com/dolphin0520/p/3920407.html 中的文章. ...

  9. python多线程(二)

    原文:http://blog.sina.com.cn/s/blog_4b5039210100esc1.html 基础不必多讲,还是直接进入python. Python代码代码的执行由python虚拟机 ...

  10. 并发和多线程(二)--线程安全、synchronized、CAS简介

    线程安全性: 当多个线程访问一个类的时候,这个类始终表示出正确的行为,那么这个类是线程安全的. 无状态的对象一定是线程安全的,例如大部分service.dao.Servlet都是无状态的. 线程安全体 ...

随机推荐

  1. 微信小程序开发中的二三事之网易云信IMSDK DEMO

    本文由作者邹永胜授权网易云社区发布. 简介 为了更好的展示我们即时通讯SDK强悍的能力,网易云信IM SDK微信小程序DEMO的开发就提上了日程.用产品的话说就是: 云信 IM 小程序 SDK 的能力 ...

  2. CF834D The Bakery

    题目链接:戳我 题意:将一个长度为n的序列分为k段,使得总价值最大.一段区间的价值表示为区间内不同数字的个数 \(n<=35000,k<=50\) 开始想的转移方程是这个样子的--\(dp ...

  3. forword和重定向有什么区别?

    一.forword 1.请求只能从同一个web中转发,当前应用之外的找不到. 2.地址栏不变. 3.共享request对象,请求链不断. 4.永久性跳转,最常用. 5.客户端方法功能跳转 二.重定向 ...

  4. [javascript]—jQuery解析本地 XML 文档

    Create a jQuery object using an XML string and obtain the value of the title node. <!doctype html ...

  5. springboot多数据源动态切换和自定义mybatis分页插件

    1.配置多数据源 增加druid依赖 完整pom文件 数据源配置文件 route.datasource.driver-class-name= com.mysql.jdbc.Driver route.d ...

  6. SpringMvc HttpMessageConverter之@ResponseBody

    我们先看HttpMessageConverter的示意图,从图片可以看出它是多么的重要.在一条必经之路截道了的感觉. 先上我的测试例子: jsp页面: <%@ page language=&qu ...

  7. C++多线程编程一

    1.C++多线程初步: #include <iostream> #include <thread> #include <Windows.h> using names ...

  8. Azure Powershell部署使用平台映像的托管Windows VM及相关问题说明

    1.脚本背景信息: a.使用平台镜像(Windows Server 2016 zh-cn)部署高性能托管磁盘虚拟机 b.虚拟机默认不开启Boot诊断 c.添加三块已经创建好的数据磁盘 d.添加已创建好 ...

  9. pycharm连接数据库出现时区jdbc问题

    unrecognized or represents more than one time zone. You must configure either the server or JDBC dri ...

  10. hdu 1233 还是畅通工程 并查集or最小生成树

    某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路 ...