(单例多例,枚举,动态代理,lombok)day23javaSE基础查漏补缺

一级目录

1.多线程下的懒汉模式

用同步方法。

Java多线程–单例模式的五种实现_makeliwei1的博客-CSDN博客_java多线程单例

2.多例模式应用场景举例:

多并发请求环境下,系统需要为每个客户端的独立请求提供单独服务的资源,但是系统总的开销是有限的,系统在并发量很大时也不可能为所有的并发请求同时提供相应的资源,否则不但系统资源消耗量大而且非常耗时。这时就可以考虑使用池的概念,也即是一种多例模式的实现。具体的应用场景,比如数据库连接池、EJB无状态会话Bean的实例池
代码实现上一般是提供一个容器类,也即是容纳资源对象的池,对象池的一些属性可以通过配置文件来配置,比如数据库连接池中容纳的Connection类型的对象数目的上限和下限、闲置连接超时时间等;然后每当应用程序请求数据库连接时,先判断池中有无空闲的连接,如有,即返回这个对象,如没有,则新建一个连接对象,并放入连接池中进行管理

3.线程池扩容和拒绝策略

底层还是集合,扩容还是跟集合的扩容一样,

他的目的是为了让线程对象重复使用,不是完全意义上的多例模式。

多例子模式就是为了固定对象个数的。

4.用单例模式创建线程池,保证系统用的线程池是唯一的。

5.看一下线程池的扩容机制。

ThreadPoolExecutor线程池及线程扩展策略_u013276888的博客-CSDN博客_线程池扩容机制

6.创建多少线程合适

对于 CPU 密集型计算,多线程本质上是提升多核 CPU 的利用率,所以对于一个 4 核的 CPU,每个核一个线程,理论上创建 4 个线程就可以了,再多创建线程也只是增加线程切换的成本。所以,对于 CPU 密集型的计算场景,理论上“线程的数量 =CPU 核数”就是最合适的。不过在工程上,线程的数量一般会设置为“CPU 核数 +1”,这样的话,当线程因为偶尔的内存页失效或其他原因导致阻塞时,这个额外的线程可以顶上,从而保证 CPU 的利用率。

对于 I/O 密集型的计算场景,比如前面我们的例子中,如果 CPU 计算和 I/O 操作的耗时是 1:1,那么 2 个线程是最合适的。如果 CPU 计算和 I/O 操作的耗时是 1:2,那多少个线程合适呢?是 3 个线程,这样 CPU 和 I/O 设备的利用率都达到了 100%。

核心*2

此方式使用的是下方第一个计算公式进行计算的。

计算公式如下:最佳线程数 =CPU 核数 * 期待CPU利用率* [ 1 +(I/O 耗时 / CPU 耗时)]
原文链接:https://blog.csdn.net/w5761499123/article/details/105906757

7.线程池概述

核心线程满了,接下来进队列,队列也满了,创建新线程,直到达到最大线程数,之后再超出,会进入拒绝rejectedExecution

8.枚举是多例模式的简写(语法糖)。

获取多个特定的对象的简写

9.枚举一般默认空参构造方法。

10.装饰者模式与动态代理的区别

装饰者模式:
就是为了给装饰者的方法增强,单纯的是为了在装饰者方法上增加其他功能。是继承的一种替代方案,可以理解为 在不改变接口的前提下,动态扩展对象的功能

例子:孙悟空七十二变
孙悟空有七十二般变化,他的每一种变化都给他带来一种附加的本领。他变成鱼儿时,就可以到水里游泳;他变成雀儿时,就可以在天上飞行。而不管悟空怎么变化,在二郎神眼里,他永远是那只猢狲。 

动态代理:
给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用;被代理的对象难以直接获得或者是不想暴露给客户端

例子:孙悟空扮演并代替高家三小姐 
孙悟空扮演高家三小姐,所以可以说孙悟空与高家三小姐具有共同的接口。 
如果猪八戒只想见见高家三小姐的娇好面容,或者谈谈天说说地,那么高家三小姐的“代理”孙悟空是允许的,但猪八戒想亲亲嘴,要搞弓虽奸,那么是不行的。 

11.动态代理代理的是接口,只能转成接口,不能强转成实现类

注意:必须使用代理人对象调用方法的功能

12.动态代理底层:采用的反射技术,会使用反射技术获取到我们调用的方法,对方法进行拦截

13.lombok注解,会自动生成get/set啥的,并真实存在于class文件中。

14.return null和return啥区别

单写return;结束无返回值方法。

return null结束有返回(对象)方法。

15.设计模式分类

创建型-高效创建对象
简单工厂(SimpleFactory)
工厂方法(FactoryMethod)
抽象工厂(Abstract Factory)
创建者(Builder)
原型(Prototype)
单例(Singleton)
多例(Multiton)

结构型-对象的组成和依赖关系
外观(Facade)
适配器(Adapter)
代理(Proxy)
装饰者(Decorator)
桥(Bridge)
组合(Composite)
享元(Flyweight)

行为型-对象的行为
模板方法(Template Method)
观察者(Observer)
状态(State)
策略(Strategy)
责任链(Chain of Responsibility)
命令(Command)
访问者(Visitor)
调停者(Mediator)
备忘录(Memento)
迭代器(Iterator)
解释器(Interpreter)

16.多线程懒汉模式下:双检锁为什么还要加volatile?

我们为什么在声明MyObject对象的时候还要给它加上volatile关键字?我们在Double-Check下已经加入了synchronized关键字,既然synchronized已经起到了多线程下原子性、有序性、可见性的作用,为什么还要加volatile呢?要解决这个问题,我们需要深入了解volatile关键字的特性,它不仅可以使变量在多个线程之间可见,而且它还具有禁止JVM进行指令重排序的功能,具体请参见JVM–从volatile深入理解Java内存模型这篇文章。

首先,我们需要明白的是:创建一个对象可以分解为如下的3行伪代码:

memory=allocate();      //1.分配对象的内存空间
ctorInstance(memory);   //2.初始化对象
instance=memory;        //3.设置instance指向刚分配的内存地址。

//上面3行代码中的2和3之间,可能会被重排序导致先3后2

也就是说,myObject = new MyObject()这句话并不是一个原子性操作,在多线程环境下有可能出现非线程安全的情况。

现在我们先假设一下,如果此时不设置volatile关键字会发生什么。

假设两个线程A、B,都是第一次调用该单例方法,线程A先执行myObject = new MyObject(),该构造方法是一个非原子操作,编译后生成多条字节码指令,由于JAVA的指令重排序,可能会先执行myObject的赋值操作,该操作实际只是在内存中开辟一片存储对象的区域后直接返回内存的引用,之后myObject便不为空了,但是实际的初始化操作却还没有执行,如果就在此时线程B进入,就会看到一个不为空的但是不完整(没有完成初始化)的MyObject对象,所以需要加入volatile关键字,禁止指令重排序优化,从而安全的实现单例。

因此我们以后应该记得,在使用Double-Check的时候,那个volatile至关重要。并不是可要可不要的。
原文链接:https://blog.csdn.net/championhengyi/article/details/77677393

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值