microsoft文档:https://docs.microsoft.com/zh-cn/previous-versions/msp-n-p/ff650316(v=pandp.10)
参考:https://blog.csdn.net/yupu56/article/details/53668688
文档:
lock:https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/lock-statement
volatile:https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/volatile#example
一. 基本
基础代码
public sealed class Singleton
{
private Singleton (){}
//使用volatile防止某线程读取到instance不为null时,instance引用的对象有可能还没有完成初始化(另一线程中还没有完成写入操作)。
private static volatile Singleton instance;
private static object syncRoot = new Object();
public static Singleton Instance
{
get
{
//此处加一个if进行优化。是因为只有在第一次创建对象的时候需要加锁。
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
lock 关键字:
- 获取给定对象的互斥 lock。执行语句块,然后在释放 lock。
- 持有 lock 时,持有 lock 的线程可以再次获取并释放 lock。
- 阻止任何其他线程获取 lock 并等待释放 lock。
volatile关键字:
- 背景:
- 出于性能原因,编译器,运行时系统甚至硬件都可能对存储器位置的读取和写入两种操作重新排列,也就是说一个字段可以由多个线程同时执行读写。
- 多个线程同时访问一个变量,CLR为了效率,允许每个线程进行本地缓存,这就导致了变量的不一致性。
- 作用:申明了volatile的字段不进行读写操作重新排列的优化。不允许线程进行本地缓存,每个线程的读写都是直接操作在共享内存上,这就保证了变量始终具有一致性。
二. 单例模式父类
缺点:无法防止子类实例化。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace DW
{
public class SingletonParent<T> where T : class, new()
{
protected SingletonParent() { }
private static volatile T instance;
private static readonly object syncRoot = new object();
public static T Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new T();
}
}
}
return instance;
}
}
}
}
三. 关于继承MonoBehaviour
- 加载脚本实例时会调用Awake
- 在初始化所有对象之后才调用Awake
- 所以,此时已经被实例化,用this将当前实例对象给instance
private void Awake()
{
if(mMyInstance == null)//防止实例化多次,出现问题,如Instantiate
{
mMyInstance = this;
}
}
网友评论