多线程状态与优先级、线程同步与Monitor类、死锁
一、线程状态

二、线程优先级

三、初步尝试多线程
class Program
{
static void Main(string[] args)
{
while (true)
{ MessagePrinter p1=new MessagePrinter();
Thread t1 = new Thread(new ThreadStart(p1.Print));
t1.Name = "t1";
t1.Priority = ThreadPriority.Highest; MessagePrinter p2 = new MessagePrinter();
Thread t2 = new Thread(new ThreadStart(p2.Print));
t2.Name = "t2";
t2.Priority = ThreadPriority.Lowest; MessagePrinter p3 = new MessagePrinter();
Thread t3 = new Thread(new ThreadStart(p3.Print));
t3.Name = "t3";
t2.Priority = ThreadPriority.Lowest; Console.WriteLine("线程启动:\n"); t1.Start();
t2.Start();
t3.Start(); Console.WriteLine("线程结束:\n");
string r= Console.ReadLine();
if (r == "")
break;
}
}
} class MessagePrinter
{
private int _sleepTime;
private static Random _random=new Random(); public MessagePrinter()
{
_sleepTime = _random.Next();
} public void Print()
{
Thread current = Thread.CurrentThread;
Console.WriteLine(string.Format("线程:{0},即将进入休眠状态:{1}毫秒", current.Name, _sleepTime));
Thread.Sleep(_sleepTime);
Console.WriteLine(string.Format("线程:{0},结束休眠", current.Name)); }
}
初识多线程
四、线程同步 与Monitor类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; /*
*
* 线程同步:
* 1、作用:是保证多个线程之间同步处理【共享数据】的
* 2、使用Monitor:
* > Enter:占用当前对象锁
* > Wait:等待
* > Pulse:让下一个其它线程开始运行
* > Exit:解除占用对象锁
* 3、一定要将Exit放到TryCatch块的finialy中,防止在占用锁后,出现异常,然后没有释放锁,导致死锁
* 4、使用Lock加锁,替代Enter和Exit;
*
* 死锁的几种情况:
* 1、互等死:线程之间互相引用,导致都不能释放
* 2、等到死:线程使用Wait后,再没有其它线程使用Pulse或PulseAll进行唤醒
* 3、异常死:在某个线程占用锁后,发生了异常,没有执行Exit释放锁操作,导致死锁
*
* */
namespace 线程同步与Monitor类
{
class Program
{
static void Main(string[] args)
{ #region 非线程同步 // IBuffer buffer = new UnSynchronuzedBuffer();//非线程同步
//IBuffer buffer = new SynchronizedBuffer();//线程同步
IBuffer buffer = new CircularBuffer();//增加缓冲区空间,从而增加效率
Random r = new Random(); Producer p = new Producer(buffer, r);
Consumer c = new Consumer(buffer, r); Thread t1 = new Thread(new ThreadStart(p.Produce));
t1.Name = "Producer"; Thread t2 = new Thread(new ThreadStart(c.Consume));
t2.Name = "Consumer"; t1.Start();
t2.Start(); #endregion #region 线程同步 #endregion Console.ReadLine();
}
} #region 共享区
public interface IBuffer
{
int Buffer
{
get;
set;
}
} /// <summary>
/// 非线程同步缓冲区
/// </summary>
public class UnSynchronuzedBuffer : IBuffer
{
private int _Buffer=-; public int Buffer
{
get
{
Console.WriteLine(string.Format(" 线程:{0},读取 {1} ",Thread.CurrentThread.Name,_Buffer));
return _Buffer;
}
set
{
Console.WriteLine(string.Format("线程:{0},写入 {1} ", Thread.CurrentThread.Name, value));
_Buffer=value;
}
} } /// <summary>
/// 线程同步,使用Monitor
/// </summary>
public class SynchronizedBuffer : IBuffer
{
private int _Buffer = -;
private int occupiedBufferCount = ; public int Buffer
{
get
{
//锁定当前对象
Monitor.Enter(this); try
{
//如果没有Buffer中没有更新数据,则进入线程等待
if (occupiedBufferCount == )
{
Console.WriteLine(string.Format(" 线程:{0},试图读取缓冲区数据", Thread.CurrentThread.Name)); DisplayState(string.Format(" Buffer是空的,线程:{0}进行等待", Thread.CurrentThread.Name)); Console.WriteLine(" ===读取等待..........");
//释放 对象锁,并进入 WaitSleepJoin状态,等待再次获取锁
//本线程再次进入Running状态时,继续向下执行。
Monitor.Wait(this);
Console.WriteLine(" ===读取结束-1..........");
} --occupiedBufferCount; Console.WriteLine(string.Format(" 线程:{0},开始读取:{1}",Thread.CurrentThread.Name,_Buffer)); //如果有其它线程,进行唤醒
Monitor.Pulse(this); //复制buffer的目的,是防止刚解锁,生成者就立马改变了数据
int bufferCopy=_Buffer; //返回副本
return bufferCopy;
}
catch (Exception ex)
{ throw;
}
finally
{
//释放对象上的锁
Monitor.Exit(this); } }
set
{
if (!Monitor.TryEnter(this, ))
{
Console.WriteLine("【set时,TryEnter失败,将使用Enter进入。】");
Monitor.Enter(this);
} if (occupiedBufferCount == )
{
Console.WriteLine(string.Format("线程:{0},试图写入", Thread.CurrentThread.Name));
DisplayState(string.Format("Buffer 已满,线程:{0}等待", Thread.CurrentThread.Name)); Console.WriteLine("===写入等待..........");
//等待缓冲区数据被读取后,再写入
Monitor.Wait(this);
Console.WriteLine("===写入等待结束-1..........");
} _Buffer = value; ++occupiedBufferCount; Console.WriteLine(string.Format("线程:{0},写入{1}", Thread.CurrentThread.Name, value)); Monitor.Pulse(this);
Monitor.Exit(this); }
} /// <summary>
/// 展示当前的操作和Buffer的状态
/// </summary>
/// <param name="operation"></param>
public void DisplayState(string operation)
{
Console.WriteLine(string.Format("{0,-35}{1,-9}{2}\n", operation, _Buffer, occupiedBufferCount));
}
} /// <summary>
/// 当生产者与消费者速度基本同步时,适当增加缓冲区空间,从而减少互等时间。
/// 使用Lock代替Monitor.Enter和Exit方法
/// </summary>
public class CircularBuffer : IBuffer
{
private int[] _Buffer = {-,-,-};
private int occupiedBufferCount = ; private int readLocation = ;//当前读取位置
private int writeLocation = ;//当前写入位置 public int Buffer
{
get
{
Monitor.Enter(this);
try
{
if (occupiedBufferCount == )
{
Console.WriteLine(string.Format(" 【Read】缓冲区为空,进入等待状态"));
Monitor.Wait(this);
Console.WriteLine(string.Format(" 【Read】等待结束")); } int readValueCopy = _Buffer[readLocation];
Console.Write(string.Format(" 【Read】线程:{0},读取:{1}", Thread.CurrentThread.Name, readValueCopy)); --occupiedBufferCount;
readLocation = (readLocation + ) % _Buffer.Length;
Console.WriteLine(CreateStateOutput()); Monitor.Pulse(this);
return readValueCopy; }
catch (Exception ex)
{
Console.WriteLine(string.Format("异常:{0}",ex.Message.ToString()));
return -;
}
finally
{
Monitor.Exit(this);
}
}
set
{
//使用lock 代替 Monitor.Enter 和 Monitor.Exit()
lock (this)
{
if (occupiedBufferCount == _Buffer.Length)
{
Console.WriteLine(string.Format("缓冲区【已满】,进入等待状态"));
Monitor.Wait(this);
} _Buffer[writeLocation] = value;
Console.Write(string.Format("已在位置{0},写入:{1}", writeLocation, value)); occupiedBufferCount++;
writeLocation = (writeLocation + ) % _Buffer.Length; Console.WriteLine(CreateStateOutput()); Monitor.Pulse(this);
}
} } private String CreateStateOutput()
{
string output = "(buffer occupied:" + occupiedBufferCount + ")\nbuffers:";
for (int i = ; i < _Buffer.Length; i++)
output += " " + string.Format("{0,2}", _Buffer[i]) + " "; output += "\n";
output += " "; for (int i = ; i < _Buffer.Length; i++)
output += "-----"; output += "\n";
output += " "; for (int i = ; i < _Buffer.Length; i++)
{
if (i == writeLocation && i == readLocation)
output += " WR ";
else if (i == writeLocation)
output += " W ";
else if (i == readLocation)
output += " R ";
else
output += " "; } output += "\n"; return output; }
}
#endregion #region 生产者/消费者
public class Producer
{
private IBuffer sharedLocation;
private Random random; public Producer(IBuffer buffer, Random random)
{
this.sharedLocation = buffer;
this.random = random;
} public void Produce()
{
for (int count = ; count <= ; count++)
{
Thread.Sleep(random.Next(, ));
sharedLocation.Buffer = count;
} Console.WriteLine(string.Format("=====生产者线程:{0},已执行完毕!", Thread.CurrentThread.Name));
} } public class Consumer
{
private IBuffer sharedLocation;
private Random random; public Consumer(IBuffer buffer, Random random)
{
this.sharedLocation = buffer;
this.random = random;
} public void Consume()
{
int sum = ;
for (int count = ; count <= ; count++)
{
Thread.Sleep(random.Next(, ));
sum+= sharedLocation.Buffer;
} Console.WriteLine(string.Format("=======消费者线程:{0},已执行完毕,SUM={1}!", Thread.CurrentThread.Name,sum));
}
}
#endregion
}
线程同步与Monitor类
五、GUI与线程同步
* Window窗体控件不是线程安全的
* Control类的Invoke方法,就是将子线程中需要对 控件进行操作时,返回主线程中进行控件操作。
namespace GUI与多线程
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
RandomLetters l1 = null;
RandomLetters l2 = null;
RandomLetters l3 = null; private void Form1_Load(object sender, EventArgs e)
{
this.FormClosing += new FormClosingEventHandler(Form1_FormClosing); l1 = new RandomLetters(label1,textBox1);
l2 = new RandomLetters(label2, textBox1);
l3 = new RandomLetters(label3, textBox1);
Thread t1 = new Thread(new ThreadStart(l1.GenerateRandomCharacters));
t1.Name = "t1";
t1.Start(); Thread t2 = new Thread(new ThreadStart(l2.GenerateRandomCharacters));
t2.Name = "t2";
t2.Start(); Thread t3 = new Thread(new ThreadStart(l3.GenerateRandomCharacters));
t3.Name = "t3";
t3.Start();
} void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
System.Environment.Exit(System.Environment.ExitCode);
} private void checkBox_CheckedChanged(object sender, EventArgs e)
{
if (sender == checkBox1)
l1.Toggle();
else if (sender == checkBox2)
l2.Toggle();
else if (sender == checkBox3)
l3.Toggle();
} } #region GUI线程处理
public class RandomLetters
{
private static Random random = new Random();
private Label output = null;//需要输出到的Label
private bool suspended = false;//是否暂停线程
private string threadName; public RandomLetters(Label lbl)
{
this.output = lbl;
} /// <summary>
/// 定义界面需要展示的字符
/// </summary>
/// <param name="displayChar"></param>
private delegate void DisplayDelegate(char displayChar); private void DisplayChar(char displayChar)
{
output.Text = threadName + ":" + displayChar;
} public void GenerateRandomCharacters()
{
threadName = Thread.CurrentThread.Name; while (true)
{
Thread.Sleep(random.Next()); lock (this)
{
while (suspended)
{
Monitor.Wait(this);
}
} //获取随机的26个大写字母中的一个
char displayChar = (Char)(random.Next() + ); //Invoke 回到能够控制 GUI控件的线程中,执行委托的方法,并将相应的参数传递过去
output.Invoke(new DisplayDelegate(DisplayChar),displayChar); } } public void Toggle()
{
suspended = !suspended;
output.BackColor = suspended ? Color.Red : Color.LightGreen; lock (this)
{
if (!suspended)
Monitor.PulseAll(this); if (txtBoxShow != null)
txtBoxShow.Text = string.Format("线程:{0},控制状态由{1}——>{2}。", Thread.CurrentThread.ManagedThreadId, !suspended, suspended) + "\r\n" + txtBoxShow.Text;
}
} private TextBox txtBoxShow;
public RandomLetters(Label lbl,TextBox txtBox)
{
this.output = lbl;
this.txtBoxShow = txtBox;
}
}
#endregion
GUI与线程同步
实现效果如下:

六、死锁
* 死锁的几种情况:
* 1、互等死:线程之间互相引用,导致都不能释放
* 2、等到死:线程使用Wait后,再没有其它线程使用Pulse或PulseAll进行唤醒
* 3、异常死:在某个线程占用锁后,发生了异常,没有执行Exit释放锁操作,导致死锁
* 4、饿 死:一直有优先级高的线程加入,优先级低的线程始终没分配到处理器进行处理,这种无限延期称为饿死
多线程状态与优先级、线程同步与Monitor类、死锁的更多相关文章
- C#多线程:深入了解线程同步lock,Monitor,Mutex,同步事件和等待句柄(中)
本篇继续介绍WaitHandler类及其子类 Mutex,ManualResetEvent,AutoResetEvent的用法..NET中线程同步的方式多的让人看了眼花缭乱,究竟该怎么去理解呢?其实, ...
- 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock
[源码下载] 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLoc ...
- “全栈2019”Java多线程第二十一章:同步代码块产生死锁的例子
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- 【转】多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(上)
本篇从Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler的类关系图开始,希望通过 本篇的介绍能对常见的线程同步方法有一个整体的认识,而对 ...
- Python多线程(2)——线程同步机制
本文介绍Python中的线程同步对象,主要涉及 thread 和 threading 模块. threading 模块提供的线程同步原语包括:Lock.RLock.Condition.Event.Se ...
- 转:C# 线程同步技术 Monitor 和Lock
原文地址:http://www.cnblogs.com/lxblog/archive/2013/03/07/2947182.html 今天我们总结一下 C#线程同步 中的 Monitor 类 和 Lo ...
- java多线程(2) 线程同步
我们对线程访问同一份资源的多个线程之间,来进行协调的这个东西,就是线程同步. 例子1:模拟了多个线程操作同一份资源,可能带来的问题: package com.cy.thread; public c ...
- Java多线程系列三——实现线程同步的方法
两种实现线程同步的方法 方法 特性 synchronized 不需要显式地加解锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 ...
- Android多线程研究(3)——线程同步和互斥及死锁
为什么会有线程同步的概念呢?为什么要同步?什么是线程同步?先看一段代码: package com.maso.test; public class ThreadTest2 implements Runn ...
随机推荐
- bay——巡检RAC命令_版本.txt
df -lhhostnamecat /etc/hostsifconfig ps -ef | grep tnsps -ef | grep asmps -ef | grep ora_ ls -l /dev ...
- IDEA 第三方jar包 使用
1,加入lib包中,在pom中添加 <dependency> <groupId>com.sss</groupId> <artifactId>包名< ...
- IT宝塔安装,Centos系统
宝塔安装地址:https://www.bt.cn/btcode.html 本文链接地址:https://www.cnblogs.com/wannengachao/p/12036716.html 版权声 ...
- Fiddler应用——使用Fiddler修改指定request/response报文
Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,分析数据,设置断点,修改请求/响应数据,查看所有的“进出”Fiddler的数据(指cookie,h ...
- 关于华为模拟器(eNSP)添加路由器启动后一直打印#号的原因
操作系统为win10 专业版 1903:1.首先打开控制面板,找到windows defender防火墙,在“允许应用通过防火墙”中把和espn相关的两个的专网和公网都勾选上,最后确定:然后重启华为模 ...
- __format__
目录 一.__format__ 一.__format__ 自定制格式化字符串 date_dic = { 'ymd': '{0.year}:{0.month}:{0.day}', 'dmy': '{0. ...
- __doc__
目录 一.__doc__ 一.__doc__ 返回类的注释信息 class Foo: '我是描述信息' pass print(Foo.__doc__) 我是描述信息 该属性无法被继承 class Fo ...
- EEPROM的操作---SPI接口和I2C接口
参考:http://blog.csdn.net/yuanlulu/article/details/6163106 ROM最初不能编程,出厂什么内容就永远什么内容,不灵活.后来出现了PROM,可以自己写 ...
- 09-Django静态文件
1.静态文件 项目中的图片.CSS.js都是静态文件,一般会将静态文件放到一个单独的目录下,也方便管理.一般会将静态文件放到一个单独的目录下,也可以放在应用的目录下,由于静态文件是全部应用都在使用的, ...
- 三、动态SQL
动态SQL MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. 动态SQL的元素 元素 作用 备注 if 判断语句 单条件分支判断 choose.whe ...