unity中多线程 (干货)简明扼要并且容易理解,绝对能使你眼前一亮

unity中多线程 (干货)简明扼要并且容易理解,绝对能使你眼前一亮

本文向您展示如何在 Unity3D 中使用单例模式和静态类。 内容简洁易懂。 绝对会让你眼前一亮。 希望您能从本文的详细介绍中有所收获。

1.静态类不能继承和被继承! (严格来说,它只能继承System.Object)也就是说,你的静态类不能继承MonoBehaviour,也不能实现该接口。

2.静态方法不能使用非静态成员! 如果你使用了很多静态方法贴图笔刷,并且你需要在方法中使用这个类的成员,那么你的成员必须是静态成员。

第2点需要注意的是:如果你想调整Unity的编辑器中的某个参数,那么这个参数不能是静态的(即使你自定义EditorWindow来修改这个值也是没有用的)。 解决方案是使用UnityEngine。 ScriptableObject存储配置(生成*.asset文件),然后运行时通过LoadAsset加载,然后更改静态成员。 至于原因,我相信也不难理解——你看到的所有Unity组件都是实例,你必须通过Unity编辑器来配置它们,所以你必须有这样一个可配置的实例。

从面向对象的角度思考:静态方法或静态类不需要依赖对象,类是唯一的; 单例的静态实例一般是唯一的对象(当然可以有多个)。 区别。 。 。 看起来也不是很大。 。 。

如果这样想并没有什么问题的话,那么回过头来对比一下两种方法:

1.静态(静态方法或静态类),代码写起来比较困难,方法调用很方便,运行效率高一点。 该逻辑是面向过程的,无法提供对加载和销毁的良好控制。

2、单例(类的静态实例),代码编写和其他类一模一样,可以继承抽象模板接口,而且Unity中参数配置也很方便unity中多线程,但是使用起来比较麻烦,有可能出错(必须通过实例调用方法),效率不如静态(但不会有太大影响)。

如果这些说法太抽象,让我给你一个常见的问题:如果你的框架有一个可以管理所有声音播放的SoundManager,你会如何实现它?

(刚开始接触AudioSource组件的时候,我以为每个声音都会由一个AudioSource来播放。但是后来发现完全没有必要。AudioSource有一个静态的PlayClipAtPoint方法来播放临时的3D音效,还有一个实例方法PlayOneShot来播放临时音效(2D和3D取决于实例的SpatialBlend),如果没有特殊需求,那么一个AudioSource循环播放背景音乐,以上两个方法在游戏中播放特效音频,这对于大多数游戏来说已经足够了。)

那么问题来了:如果你的SoundManager播放声音的方法是静态的,那么代码中必须通过各种方式获取AudioSource组件(创建新组件或者获取特定GameObject下的组件)——因为保存这个组件的变量必须是静态的,所以不能通过Unity的编辑器来赋值。 如果不读代码,用户根本不知道这是一个什么样的组件获取过程。 如果我破坏了这个进程(同名的对象,包括互斥的组件等),那么这个Manager很可能会出现不可预测的异常。

线程中断_unity中多线程_线程中的实体基本不拥有资源

继承 MonoBehaviour 和 RequireComponent(typeof(AudioSource)) 比“为了静态而静态”的代码更加方便和健壮。

其实到这里我们基本可以总结一下什么时候需要使用单例:

1、只要你的类需要将其他组件保存为变量,就必须使用单例;

2、只要需要在Unity编辑器上配置参数,就必须使用单例;

3、只要你的manager需要控制加载顺序,就需要使用单例(比如热更新后加载ResourcesManager);

当然,这些只是“必要”unity中多线程,而不是“必须”。 两者最大的区别在于,一个是书写方便,一个是使用方便。 编写方便的代价是每次调用都添加一个实例,使用方便的代价是放弃面向对象和Unity的“所见即所得”。 哪个更重要由您决定。

另一方面,就像“为了静态而静态”一样,“为了单例而单例”也是一种不合理的设计。 这个解释还是那么模糊,所以就给自己定义一个最简单的规则——如果你的单例类没有任何需要保存状态的变量,那么这个类中的所有方法都可以是静态方法,这个类也可以是静态类。

补充:从例子开始,理解单例模式和静态块

即使你没有使用过其他设计模式,你也一定接触过单例模式。 例如,Spring中的bean默认是单例模式,并且这个bean的所有实例实际上都是相同的。

单例模式的使用场景

什么是单例模式? 单例模式(Singleton)也称为单例模式。 其目的是确保一个类在系统中只有一个实例,并提供一个全局访问点来访问它。 从这一点可以看出,单例模式的出现是一种解决方案,保证系统中某个类只有一个实例,并且该实例易于外界访问,从而方便对类的控制。实例数量并节省系统资源。

使用单例模式当然有其原因和好处。 单例模式适合在以下场景使用:

1、如果存在频繁实例化然后销毁,即频繁new对象,可以考虑单例模式;

2. 创建时间过长或消耗资源过多但使用频繁的对象;

3、频繁访问IO资源的对象,例如数据库连接池或者本地文件;

下面举几个例子来说明:

1、网站在线人数统计;

其实它是一个全局计数器,也就是说所有用户在同一时刻获得的在线人数是相同的。 为了达到这个要求,计数器必须是全局唯一的,可以使用单例模式来实现。 当然这里不包括分布式场景,因为计数是保存在内存中的,必须保证线程安全。 下面的代码是一个简单的计数器实现。

public class Counter {   
    private static class CounterHolder{
        private static final Counter counter = new Counter();
    }
    private Counter(){
        System.out.println("init...");
    }
    public static final Counter getInstance(){
        return CounterHolder.counter;
    }
    private AtomicLong online = new AtomicLong();
    public long getOnline(){
        return online.get();
    }
    public long add(){
        return online.incrementAndGet();
    }
}

2、配置文件访问类;

项目中经常需要一些环境相关的配置文件,比如短信通知相关、邮件相关的配置文件。 例如属性文件,这里是读取属性文件配置的示例。 如果使用Spring,可以使用@PropertySource注解来实现。 默认是单例模式。 如果不使用单例,每次都要创建一个新的对象,并且每次都要重新读取配置文件,这极大地影响了性能。 如果使用单例模式,则只需要读取一次即可。 以下是文件访问单例类的简单实现:

public class SingleProperty {
    private static Properties prop;
    private static class SinglePropertyHolder{
        private static final SingleProperty singleProperty = new SingleProperty();
    }
    /**
    * config.properties 内容是 test.name=kite 
    */
    private SingleProperty(){
        System.out.println("构造函数执行");
        prop = new Properties();
        InputStream stream = SingleProperty.class.getClassLoader()
                .getResourceAsStream("config.properties");
        try {
            prop.load(new InputStreamReader(stream, "utf-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SingleProperty getInstance(){
        return SinglePropertyHolder.singleProperty;
    }    
 
    public String getName(){
        return prop.get("test.name").toString();
    }
    public static void main(String[] args){
        SingleProperty singleProperty = SingleProperty.getInstance();
        System.out.println(singleProperty.getName());
    }
}

unity中多线程_线程中断_线程中的实体基本不拥有资源

3、数据库连接池的实现,包括线程池。

之所以需要池化,是因为创建新连接非常耗时。 如果每次有新任务来就创建新的连接,对性能的影响就太大了。 因此,一般的做法是在应用程序内部维护一个连接池,这样当有任务进来时,如果有空闲连接,就可以直接使用,省去了初始化的成本。

因此,使用单例模式,可以实现一个应用程序中只有一个线程池,所有需要连接的任务都必须从这个连接池中获取连接。

如果不使用单例,应用程序中就会存在多个连接池,这是没有意义的。 如果使用Spring并集成druid或c3p0,这些成熟的开源数据库连接池一般默认都是以单例模式实现的。

如何实现单例模式

如果你在书籍或者网站上搜索单例模式的实现,一般都会介绍方法5和方法6。 其中一些随着Java版本的增加和多线程技术的使用而变得不太实用。 这里介绍两种既高效又线程安全的方法。

1.静态内部类方法

public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE; 
    }  
}

这种写法还是利用了JVM自身的机制来保证线程安全问题。 由于SingletonHolder是私有的,除了getInstance()方法之外没有办法访问它,所以它是惰性的; 同时,读取实例时不进行同步。 无性能缺陷; 不依赖JDK版本。 上面的两个例子就是这样实现的。

2. 枚举法

public enum SingleEnum {
    INSTANCE;
    SingleEnum(){
        System.out.println("构造函数执行");
    }
    public String getName(){
        return "singleEnum";
    }
    public static void main(String[] args){
        SingleEnum singleEnum = SingleEnum.INSTANCE;
        System.out.println(singleEnum.getName());
    }
}

我们可以通过 SingleEnum.INSTANCE 访问实例。 此外,默认情况下创建枚举是线程安全的,并且可以防止反序列化重新创建新对象。

静态块 什么是静态块?

1.随着类的加载而执行,只执行一次,并且优先于main函数。 具体来说,静态代码块由类调用。 调用类时,先执行静态代码块,再执行main函数;

2、静态代码块实际上是针对类进行初始化的,而构造代码块是针对对象进行初始化的;

3、静态代码块中的变量是局部变量,本质上和普通函数中的局部变量没有什么区别;

4、一个类中可以有多个静态代码块;

他是这样写的:

static {
        System.out.println("static executed");
    }

看一下下面的完整示例:

public class SingleStatic {
    static {
        System.out.println("static 块执行中...");
    }
    {
        System.out.println("构造代码块 执行中...");
    }
    public SingleStatic(){
        System.out.println("构造函数 执行中");
    }
    public static void main(String[] args){
        System.out.println("main 函数执行中");
        SingleStatic singleStatic = new SingleStatic();
    }
}

他的执行结果如下:

unity中多线程_线程中断_线程中的实体基本不拥有资源

静态块执行...

main函数正在执行

构造代码块执行...

构造函数执行

可以看出他们的执行顺序是:

1.静态代码块

2、主要功能

3. 构造代码块

4.构造函数

利用静态代码块只在类加载时执行,并且只执行一次的特性人物立绘,也可以用来实现单例模式,但它不是延迟加载,也就是说每次类加载时都会主动触发实例化已加载。

以上内容是如何在Unity3D中使用单例模式和静态类。 你学到了知识或技能了吗? 如果您想学习更多技能或者丰富自己的知识库,欢迎关注易速云行业资讯频道。

文章来源:https://m.yisu.com/zixun/447734.html