一、线程状态

二、线程优先级

三、初步尝试多线程

 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类、死锁的更多相关文章

  1. C#多线程:深入了解线程同步lock,Monitor,Mutex,同步事件和等待句柄(中)

    本篇继续介绍WaitHandler类及其子类 Mutex,ManualResetEvent,AutoResetEvent的用法..NET中线程同步的方式多的让人看了眼花缭乱,究竟该怎么去理解呢?其实, ...

  2. 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock

    [源码下载] 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLoc ...

  3. “全栈2019”Java多线程第二十一章:同步代码块产生死锁的例子

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  4. 【转】多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(上)

    本篇从Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler的类关系图开始,希望通过 本篇的介绍能对常见的线程同步方法有一个整体的认识,而对 ...

  5. Python多线程(2)——线程同步机制

    本文介绍Python中的线程同步对象,主要涉及 thread 和 threading 模块. threading 模块提供的线程同步原语包括:Lock.RLock.Condition.Event.Se ...

  6. 转:C# 线程同步技术 Monitor 和Lock

    原文地址:http://www.cnblogs.com/lxblog/archive/2013/03/07/2947182.html 今天我们总结一下 C#线程同步 中的 Monitor 类 和 Lo ...

  7. java多线程(2) 线程同步

    我们对线程访问同一份资源的多个线程之间,来进行协调的这个东西,就是线程同步.   例子1:模拟了多个线程操作同一份资源,可能带来的问题: package com.cy.thread; public c ...

  8. Java多线程系列三——实现线程同步的方法

    两种实现线程同步的方法 方法 特性 synchronized 不需要显式地加解锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 ...

  9. Android多线程研究(3)——线程同步和互斥及死锁

    为什么会有线程同步的概念呢?为什么要同步?什么是线程同步?先看一段代码: package com.maso.test; public class ThreadTest2 implements Runn ...

随机推荐

  1. django之查询操作及开启事务

    目录 聚合查询 aggregate 聚合函数 分组查询 annotate F与Q查询 F查询 Q查询 ORM操作事务 django中开启事务 聚合查询 aggregate 操作外键字段管理数据的时候, ...

  2. Java学习笔记(7)---流(Stream),文件(File)

    1.Stream流 a.定义: Java.io 包几乎包含了所有操作输入.输出需要的类.所有这些流类代表了输入源和输出目标. Java.io 包中的流支持很多种格式,比如:基本类型.对象.本地化字符集 ...

  3. 压测工具ab

    1.安装abyum install httpd-tools 2.使用ab -n 2000 -c 2 http://www.cctv.com-n:总的请求数-c:并发数-k:是否开启长连接 3.结果举例 ...

  4. Python3——根据m3u8下载视频(上)之urllib.request

    干活干活,区区懒癌已经阻挡不了澎湃的洪荒之力了...... 运行环境:Windows基于python3.6 ---------------------------------------------- ...

  5. JavaScript内置对象及常见API

    一.全局属性 Infinity:表示正无穷大 NaN:非数字值 undefined:未定义的值 decodeURI():对encodeURI()转义的字符串解码 decodeURIComponent( ...

  6. C语言程序设计100例之(5):分解质因数

    例5    分解质因数 题目描述 将一个正整数分解质因数.例如:输入90,输出 90=2*3*3*5. 输入 输入数据包含多行,每行是一个正整数n (1<n <100000) . 输出 对 ...

  7. Unity TextMeshPro 一键生成工具

    本文参考了这片博客文章,在此基础上进行优化和改进: https://blog.csdn.net/akof1314/article/details/80868869 先截张效果图: TextMeshPr ...

  8. 全栈工程师对Python面试中is和==区别的详细解说!看完真的学到了!

    面试实习生的时候,当问到 is 和 == 的区别时,很多同学都答不上来,搞不清两者什么时候返回一致,什么时候返回不一致.本文我们来看一下这两者的区别. 我们先来看几个例子: a = "hel ...

  9. Linux网络——修改配置文件

    Linux网络——修改配置文件 摘要:本文主要学习了如何通过修改配置文件来设置网络参数. 配置文件 通过修改系统的配置文件为系统设置网络参数,这种方式的优点是可以永久保存,计算机重启后仍然生效.缺点是 ...

  10. Javase之多线程(2)

    多线程(2) 线程的生命周期 新建:创建线程对象 就绪:有执行资格,没有执行权 运行:有资格运行,有执行权 ​ 阻塞:由一些操作让线程处于改状态.没有执行资格,没有执行权,而通过另一些操作激活它,激活 ...