2022.1.21刷题笔记

2022.1.21刷题笔记,第1张

2022.1.21刷题笔记 四大修饰符 - private(私有的)

​ private可以修饰成员变量,成员方法,构造方法,不能修饰类(此刻指的是外部类,内部类不加以考虑)。被private修饰的成员只能在其修饰的本类中访问,在其他类中不能调用,但是被private修饰的成员可以通过set和get方法向外界提供访问方式

- default(默认的)

​ defalut即不写任何关键字,它可以修饰类,成员变量,成员方法,构造方法。被默认权限修饰后,其只能被本类以及同包下的其他类访问。

- protected(受保护的)

​ protected可以修饰成员变量,成员方法,构造方法,但不能修饰类(此处指的是外部类,内部类不加以考虑)。被protected修饰后,只能被同包下的其他类访问。如果不同包下的类要访问被protected修饰的成员,这个类必须是其子类。

- public(公共的)

​ public是权限最大的修饰符,他可以修饰类,成员变量,成员方法,构造方法。被public修饰后,可以再任何一个类中,不管同不同包,任意使用。

publicprotecteddefaultprivate同一个类√√√√同一个包√√√子类√√不同包√ 枚举(enum)

​ 枚举(enum)类型是java 5新增的特性,它是一种新的类型,允许用常量来表示特定的数据片断,而且全部都以类型安全的形式来表示,是特殊的类,可以拥有成员变量和方法。

hashMap,hashTable,concurrentHashMap

​ hashMap在单线程中使用大大提高效率,在多线程的情况下使用hashTable来确保安全。hashTable中使用synchronized关键字来实现安全机制,但是synchronized是对整张hash表进行锁定即让线程独享整张hash表,在安全同时造成了浪费。concurrentHashMap采用分段加锁的机制来确保安全。(jdk1.8后。concurrentHashMap取消了segment分段锁,采用cas和synchronized来保证并发安全)

java异常处理 throw用于抛出异常 throws 关键字可以在方法上声明该方法要抛出的异常、然后在方法内部通过throw抛出异常对象。 try是用于检测被包住的语句块是否出现异常,如果有异常,则抛出异常,并执行catch语句。 cacth用于捕获从try中抛出的异常并作出处理。 finally语句块是不管有没有出现异常都要执行的内容。 单例模式 定义

​ 确保一个类只有一个实例,并提供该实例的全局访问点。这样做的好处是:有些实例,全局只需要一个就够了,使用单例模式就可以避免一个全局使用的类,频繁的创建与销毁,耗费系统资源。

设计要素

一个私有构造函数(确保只能单例类自己创建实例)一个私有静态变量(确保只有一个实例)一个公有静态函数(给使用者提供调用方法)

简单来说就是,单例类的构造方不让其他人修改和使用;并且单例类自己只创建一个实例,这个实例,其他人也无法修改和直接使用;然后单例类提供一个调用方法,想用这个实例,只能调用。这样就确保了全局只创建了一个实例。

单例模型6种实现及各实现的优缺点 一、懒汉式(线程不安全)

实现

public class Singleton {
    private static Singleton uniqueInstance;
    private Singleton() {}
    public static Singleton getUniqueInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}

说明:先不创建实例,当第一次被调用时,在创建实例,所以被称为懒汉式。

优点:延迟了实例化,如果不需要使用该类,就不会被实例化,节约了系统资源。

缺点:线程不安全,多线程环境下,如果多个线程同时进入了 if (uniqueInstance == null) ,若此时还未实例化,也就是uniqueInstance == null,那么就会有多个线程执行 uniqueInstance = new Singleton(); ,就会实例化多个实例;

二、饿汉式(线程安全)

实现:

public class Singleton{
	private static Singleton uniqueInstance = new Singleton();
	private Singleton(){
	}
	public static Singleton getUniqueInstance(){
		return uniqueInstance;
	}
}

说明:先不管需不需要使用这个实例,直接先实例化好实例(饿死鬼一样,所以称为饿汉式),然后当需要使用的时候,直接调方法就可以使用了

优点:提起实例化好了一个实例,避免了线程不安全问题的出现,

缺点:直接实例化了实例,不再延迟实例化;若系统没有使用这个实例,或者系统运行很久之后才需要使用这个实例,都会使 *** 作系统的资源浪费。

(三)懒汉式(线程安全)

实现:

public class Singleton {
    private static Singleton uniqueInstance;

    private static singleton() {
    }

    private static synchronized Singleton getUinqueInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }

}

说明: 实现和 线程不安全的懒汉式 几乎一样,唯一不同的点是,在get方法上 加了一把 锁。如此一来,多个线程访问,每次只有拿到锁的的线程能够进入该方法,避免了多线程不安全问题的出现。

优点: 延迟实例化,节约了资源,并且是线程安全的。

缺点: 虽然解决了线程安全问题,但是性能降低了。因为,即使实例已经实例化了,既后续不会再出现线程安全问题了,但是锁还在,每次还是只能拿到锁的线程进入该方***使线程阻塞,等待时间过长。

(四)双重检查锁实现(线程安全)

实现:

public class Singleton {

    private volatile static Singleton uniqueInstance;

    private Singleton() {
    }

    public static Singleton getUniqueInstance() {
        if (uniqueInstance == null) {
            synchronized (Singleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }  
}

说明: 双重检查数相当于是改进了 线程安全的懒汉式。线程安全的懒汉式 的缺点是性能降低了,造成的原因是因为即使实例已经实例化,依然每次都会有锁。而现在,我们将锁的位置变了,并且多加了一个检查。 也就是,先判断实例是否已经存在,若已经存在了,则不会执行判断方法内的有锁方法了。 而如果,还没有实例化的时候,多个线程进去了,也没有事,因为里面的方法有锁,只会让一个线程进入最内层方法并实例化实例。如此一来,最多最多,也就是第一次实例化的时候,会有线程阻塞的情况,后续便不会再有线程阻塞的问题。

为什么使用 volatile 关键字修饰了 uniqueInstance 实例变量 ?

uniqueInstance = new Singleton(); 这段代码执行时分为三步:

    为 uniqueInstance 分配内存空间初始化 uniqueInstance将 uniqueInstance 指向分配的内存地址

正常的执行顺序当然是 1>2>3 ,但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1>3>2。
单线程环境时,指令重排并没有什么问题;多线程环境时,会导致有些线程可能会获取到还没初始化的实例。
例如:线程A 只执行了 1 和 3 ,此时线程B来调用 getUniqueInstance(),发现 uniqueInstance 不为空,便获取 uniqueInstance 实例,但是其实此时的 uniqueInstance 还没有初始化。

解决办法就是加一个 volatile 关键字修饰 uniqueInstance ,volatile 会禁止 JVM 的指令重排,就可以保证多线程环境下的安全运行。

优点: 延迟实例化,节约了资源;线程安全;并且相对于 线程安全的懒汉式,性能提高了。

缺点: volatile 关键字,对性能也有一些影响。

(五)静态内部类实现(线程安全)

实现:

public class Singleton {

    private Singleton() {
    }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getUniqueInstance() {
        return SingletonHolder.INSTANCE;
    }

}

说明: 首先,当外部类 Singleton 被加载时,静态内部类 SingletonHolder 并没有被加载进内存。当调用 getUniqueInstance() 方法时,会运行 return SingletonHolder.INSTANCE; ,触发了 SingletonHolder.INSTANCE ,此时静态内部类 SingletonHolder 才会被加载进内存,并且初始化 INSTANCE 实例,而且 JVM 会确保 INSTANCE 只被实例化一次。

优点: 延迟实例化,节约了资源;且线程安全;性能也提高了。

(六)枚举类实现(线程安全)

实现:

public enum Singleton {

    INSTANCE;

    //添加自己需要的 *** 作
    public void doSomeThing() {

    }

}

说明: 默认枚举实例的创建就是线程安全的,且在任何情况下都是单例。

优点: 写法简单,线程安全,天然防止反射和反序列化调用。

防止反序列化
**序列化:**把java对象转换为字节序列的过程;
反序列化: 通过这些字节序列在内存中新建java对象的过程;
说明: 反序列化 将一个单例实例对象写到磁盘再读回来,从而获得了一个新的实例。
我们要防止反序列化,避免得到多个实例。
枚举类天然防止反序列化。
其他单例模式 可以通过 重写 readResolve() 方法,从而防止反序列化,使实例唯一重写 readResolve() :

private` `Object readResolve() ``throws` `ObjectStreamException{``    ``return` `singleton;``}
四、单例模式的应用场景

应用场景举例:

网站计数器。应用程序的日志应用。Web项目中的配置对象的读取。数据库连接池。多线程池。…

使用场景总结:

频繁实例化然后又销毁的对象,使用单例模式可以提高性能。经常使用的对象,但实例化时耗费时间或者资源多,如数据库连接池,使用单例模式,可以提高性能,降低资源损坏。使用线程池之类的控制资源时,使用单例模式,可以方便资源之间的通信。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5709371.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存