多线程-3(同步)

简介: SemaphoreSlim类代码:

SemaphoreSlim类

代码:

View Code

image.png

主线程启动,创建SemaphoreSlim的一个实例,在构造函数中指定允许并发线程数量,启动6个不同名称和不同初始运行时间的线程,借助信号系统限制访问数据的并发数, 只允许4个线程获取, 注意:.当线程1完成后,线程0才进行授权访问。

 

AutoResetEven类

 

View Code

image.png

AutoResetEvent类采用的是内核时间模式,所以等待时间不能太长。使用ManualResetEventslim类更好。

ManualResetEventSlim类

 

static ManualResetEventSlim mainEvent = new ManualResetEventSlim(false);         staticvoid TravleThroughGates(string threadName,int seconds)         {             Console.WriteLine("{0} falls to sleep",threadName);             Thread.Sleep(TimeSpan.FromSeconds(seconds));             Console.WriteLine("{0} waits for  the gates to open!",threadName);             mainEvent.Wait();//            Console.WriteLine("{0} enters the gates!", threadName);         }         staticvoid Main(string[] args)         {             var t1 = new Thread(() => TravleThroughGates("threadName 1", 5));             var t2 = new Thread(() => TravleThroughGates("threadName 2", 6));             var t3 = new Thread(() => TravleThroughGates("threadName 3", 12));             t1.Start();             t2.Start();             t3.Start();             Thread.Sleep(TimeSpan.FromSeconds(6));             Console.WriteLine("The gates are now open!");             mainEvent.Set();//            Thread.Sleep(TimeSpan.FromSeconds(2));             mainEvent.Reset();//将事件状态设置为非终止,从而导致线程受阻            Console.WriteLine("The gates have been closed!");             Thread.Sleep(TimeSpan.FromSeconds(10));             Console.WriteLine("The gates are now open for the seconds time!");             mainEvent.Set();             Thread.Sleep(TimeSpan.FromSeconds(2));             Console.WriteLine("The gates have been closed!");             mainEvent.Reset();         }

这里启动了三个线程,同时进行等待。ManualResetEventSlim 的set是允许准备好的线程接受信号并继续工作。

CountDownEvent类

CountDownEvent信号类来等待直到一定数量的操作完成。

static CountdownEvent countdownEvent = new CountdownEvent(2);         staticvoid PerformOperation(string message,int seconds)         {             Thread.Sleep(TimeSpan.FromSeconds(seconds));             Console.WriteLine(message);             countdownEvent.Signal();         }         staticvoid Main(string[] args)         {             Console.WriteLine("Starting two operations");             var t1 = new Thread(() => PerformOperation("Operation 1 is completd", 4));             var t2 = new Thread(() => PerformOperation("Operation 2 is completd", 8));             t1.Start();             t2.Start();             countdownEvent.Wait();             Console.WriteLine("Both operation have been completd");             countdownEvent.Dispose();         }

 image.png

启动两个线程,当它们执行完成后会发生信号。一旦第二个线程完成,主程序会从等待CountdownEvent的状态中返回并继续执行。当针对需要等待多个异步操作的情形,方法非常遍历。当然如果某个线程出现死锁等情况,一直等待下,那么会一直等待。

Barrier类

Barrier类组织多个线程及时在某个时刻碰面。并提供了一个回调函数,每次线程调用了SignalAndWait方法后该回调函数会执行

static Barrier barrier = new Barrier(2, b => Console.WriteLine("End of  phase {0}", b.CurrentPhaseNumber + 1));         staticvoid PlayMusic(string name,string messages,int seconds)         {             for (int i = 0; i < 3; i++)             {                 Console.WriteLine("-----------------------------");                 Thread.Sleep(TimeSpan.FromSeconds(seconds));                 Console.WriteLine("{0} starts to {1}", name, messages);                 Thread.Sleep(TimeSpan.FromSeconds(seconds));                 Console.WriteLine("{0} finshes to {1}", name, messages);                 barrier.SignalAndWait();             }         }         staticvoid Main(string[] args)         {             var t1 = new Thread(() => PlayMusic("the guitarist", "play an amazing solo", 5));             var t2 = new Thread(() => PlayMusic("the singer", "sing his song", 2));             t1.Start();             t2.Start();         }

使用Barrier,指定我们想同步两个线程。这两个线程任意一个调用了SignalAndWait方法后,会执行一个回调来打印出阶段

image.png

ReaderWriterLockSlim

ReaderWriterLockSlim类来创建一个线程安全的机制,在多线程中对一个集合进行读写操作。ReaderWriterLockSlim代表一个管理资源访问的锁,允许多个线程同时读取,以及独占写。

View Code

image.png

同时运行了三个程序来从字典中读取数据,还有另外两个线程向该字典中写入数据,使用ReaderWriterLockSlim类实现线程安全。

这里使用两种锁:读锁允许多线程读取数据,写锁在被释放前会阻塞了其他线程的所有操作,先获取读锁后读取数据,如果发现必须修改底层集合,只需使用EnterWriterLock方法升级锁,然后快速执行写操作。

SpanWait类

如果不使用内核模型的方式来使线程等待。SpanWait是一个混合同步结构,设计为使用用户模式等待一段时间,然后切换到内核模式以节省CPU时间

staticvolatilebool isCompleted = false;//volatile允许多个线程访问,呈现最新的        staticvoid UserModelWait()         {             while(!isCompleted)             {                 Console.WriteLine(".");             }             Console.WriteLine("Waiting is complete");         }         staticvoid HybridSpinWait()         {             var w = new SpinWait();             while (!isCompleted)             {                 w.SpinOnce();                 Console.WriteLine(w.NextSpinWillYield);             }             Console.WriteLine("Waiting is complete");         }         staticvoid Main(string[] args)         {             var t1 = new Thread(UserModelWait);             var t2 = new Thread(HybridSpinWait);             Console.WriteLine("Running user mode waiting");             t1.Start();             Thread.Sleep(20);             isCompleted = true;             Thread.Sleep(TimeSpan.FromSeconds(1));             isCompleted = false;             Console.WriteLine("Running hybrid SpinWait construct waiting");             Thread.Sleep(5);             isCompleted = true;         }

image.png

定义一个线程,将执行一个无止境的循环,直到20毫秒后主线程设置isCompleted变量为true,我们可以试验周期为20-30秒,通过windows任务管理器测量CPU的负载情况。

用volatie关键字来声明iscompleted静态字段,volatie字段不会被编辑器和处理器优化,只能被单个线程访问。

相关文章
|
25天前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
【6月更文挑战第20天】在Java多线程编程中,`synchronized`和`Lock`是两种关键的同步机制。`synchronized`作为内置关键字提供基础同步,简单但可能不够灵活;而`Lock`接口自Java 5引入,提供更复杂的控制和优化性能的选项。在低竞争场景下,`synchronized`性能可能更好,但在高并发或需要精细控制时,`Lock`(如`ReentrantLock`)更具优势。选择哪种取决于具体需求和场景,理解两者机制至关重要。
|
25天前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
【6月更文挑战第20天】Java多线程同步始于`synchronized`关键字,保证单线程访问共享资源,但为应对复杂场景,`Lock`接口(如`ReentrantLock`)提供了更细粒度控制,包括可重入、公平性及中断等待。通过实战比较两者在高并发下的性能,了解其应用场景。不断学习如`Semaphore`等工具并实践,能提升多线程编程能力。从同步起点到专家之路,每次实战都是进步的阶梯。
|
25天前
|
Java 程序员
从0到1,手把手教你玩转Java多线程同步!
【6月更文挑战第20天】从0到1学Java多线程同步:理解线程同步关键,掌握`synchronized`用法,探索`Lock`接口,实战演练并进阶学习锁升级、`Condition`及死锁预防,成为多线程大师!
|
3天前
|
安全 算法 Linux
【Linux】线程安全——补充|互斥、锁|同步、条件变量(下)
【Linux】线程安全——补充|互斥、锁|同步、条件变量(下)
12 0
|
3天前
|
存储 安全 Linux
【Linux】线程安全——补充|互斥、锁|同步、条件变量(上)
【Linux】线程安全——补充|互斥、锁|同步、条件变量(上)
10 0
|
28天前
|
数据挖掘 调度 开发者
Python并发编程的艺术:掌握线程、进程与协程的同步技巧
并发编程在Python中涵盖线程、进程和协程,用于优化IO操作和响应速度。`threading`模块支持线程,`multiprocessing`处理进程,而`asyncio`则用于协程。线程通过Lock和Condition Objects同步,进程使用Queue和Pipe通信。协程利用异步事件循环避免上下文切换。了解并发模型及同步技术是提升Python应用性能的关键。
43 5
|
5天前
|
存储 安全 Java
Java面试题:请解释Java内存模型,并说明如何在多线程环境下使用synchronized关键字实现同步,阐述ConcurrentHashMap与HashMap的区别,以及它如何在并发环境中提高性能
Java面试题:请解释Java内存模型,并说明如何在多线程环境下使用synchronized关键字实现同步,阐述ConcurrentHashMap与HashMap的区别,以及它如何在并发环境中提高性能
9 0
|
10天前
|
安全 NoSQL Java
网络安全-----Redis12的Java客户端----客户端对比12,Jedis介绍,使用简单安全性不足,lettuce(官方默认)是基于Netty,支持同步,异步和响应式,并且线程是安全的,支持R
网络安全-----Redis12的Java客户端----客户端对比12,Jedis介绍,使用简单安全性不足,lettuce(官方默认)是基于Netty,支持同步,异步和响应式,并且线程是安全的,支持R
|
1月前
|
安全 Java 开发者
Java并发编程的艺术:解锁多线程同步的奥秘
本文将深入探讨Java并发编程的核心概念,揭示多线程环境下同步机制的工作原理与实践技巧。我们将从基础的synchronized关键字讲起,逐步过渡到高级的Lock接口和并发工具类,最后通过实例分析来加深理解。文章不仅旨在为初学者提供一个清晰的并发编程入门指南,同时也希望能够帮助有一定经验的开发者巩固和提升他们的并发处理能力。
|
14天前
|
安全 Java
解决Java中多线程同步问题的方案
解决Java中多线程同步问题的方案