多线程状态与优先级、线程同步与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 ...
随机推荐
- 当您解开后您从 Internet 上下载的压缩的文件时,文件的修改日期更改为您提取它的日期
用鼠标右键单击该压缩的文件,然后单击属性. 单击常规选项卡,请单击取消阻止,然后单击确定. 从压缩文件中提取文件.
- django models 数据库操作
django models 数据库操作 创建模型 实例代码如下 from django.db import models class School(models.Model): pass class ...
- /dev/random 和 /dev/urandmon的差别
最近使用这两个设备的时候,发现 /dev/random生成随机数很慢:于是就查了查: 这两个设备的差异在于:/dev/random的random pool依赖于系统中断,因此在系统的中断数不足时,/d ...
- Python-判断回文
# 回文单词是从左到右和从右到左读相同的单词. # 例如:"detartrated"和"evitative"是回文 str_in = input('Input: ...
- TensorFlow从1到2(十一)变分自动编码器和图片自动生成
基本概念 "变分自动编码器"(Variational Autoencoders,缩写:VAE)的概念来自Diederik P Kingma和Max Welling的论文<Au ...
- Vue动态加载图片图片不显示
图片是放在assets文件夹下的 使用require进行解决 图片不显示的原因 在webpack,将图片放在assets中,会将图片图片来当做模块来用,因为是动态加载的,所以url-loader将无法 ...
- 剑指Offer-35.两个链表的第一个公共结点(C++/Java)
题目: 输入两个链表,找出它们的第一个公共结点. 分析: 先统计两个链表的长度,计算他们的差值,然后将两个链表对齐,再去寻找公共节点即可. 程序: C++ class Solution { publi ...
- LG1840 Color the Axis 线段树
菜的人就要写简单题 为了练习手速来写这样一道 珂朵莉树 线段树简单题 没啥可说的,注意修改操作中要判一下 val=0 #include<bits/stdc++.h> using names ...
- 转载:如何严格限制session在30分钟后过期!
如何严格限制session在30分钟后过期!1.设置客户端cookie的lifetime为30分钟:2.设置session的最大存活周期也为30分钟:3.为每个session值加入时间戳,然后在程序调 ...
- Python与用户交互
目录 一.为什么交互? 二.如何交互? 三.Python2的交互 一.为什么交互? 让我们来回顾计算机的发明有何意义,计算机的发明是为了奴役计算机,解放劳动力.假设我们现在写了一个ATM系统取代了 ...