内部类-线程池-设计模式

本文介绍了Java中的四种内部类:成员内部类、静态内部类、局部内部类和匿名内部类,详细解释了它们的特点和使用场景。同时,文章探讨了线程池的概念,分析了线程池在提高服务器性能方面的作用,以及如何创建和配置线程池,如Executors提供的不同线程池类型。此外,还讨论了设计模式的重要性,强调了面向对象设计原则和23种经典设计模式的应用价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

方法内部能不能定义类?
可以,是方法内部类

请说明定义内部类的方式,并说明适用于什么情况
(1)成员内部类:定义在另一个类(外部类)的内部,而且与成员方法和属性平级,属于类的一个成员,可以用private,默认,protected,public四个访问修饰符修饰。
外部类无法直接访问成员内部类的方法和属性,需要通过内部类的一个实例来访问。
调用方式:外部类名.内部类名 实例名 = 外部类实例名.new 内部类构造方法(参数)。
(2)静态内部类:被static修饰的成员内部类叫静态内部类。
调用方式:外部类名.内部类名 实例名 = new 外部类名.内部类名(参数)。
(3)局部内部类:定义在代码块或方法体内的类叫局部内部类。
局部内部类只能在代码块和方法体内使用(如创建对象和使用类对象等)。
(4)匿名内部类:特殊的局部内部类。
必须继承一个类(抽象的、非抽象的都可以)或者实现一个接口。如果父类(或者父接口)是抽象类,则匿名内部类必须实现其所有抽象方法。
只能使用一次,创建实例之后,类定义会立即消失。创建:父类(接口) 实例名 = new 父类(){
//匿名内部类需要实现的功能。
}
匿名内部类不能再是抽象类,因为匿名内部类在定义之后,会立即创建一个实例。
匿名内部类不能定义构造方法,匿名内部类没有类名,无法定义构造方法,但是,匿名内部类拥有与父类相同的所有构造方法。
可以定义代码块,用于实例的初始化。

普通成员内部类能不能直接访问外部类的普通成员?
普通成员内部类可以直接访问外部类的成员,如上例:内部类中的innerMethod()方法:
public void innerMethod(){
int num = 40;
System.out.println(OuterClass.this.num);//外部类的成员变量;
System.out.println(this.num);//30
System.out.println(num);//40
System.out.println(name);
}

静态成员内部类能不能直接访问外部类的普通成员?能不能访问外部类的静态成员?
静态内部类
1.不能访问外部类的非静态成员(变量或者方法)。
2.可以访问外部类的静态成员。

什么时候会使用匿名内部类?
有些情况下,某些类创建对象一次后再也不使用了。这种情况下就可以不提供有名字的类,而是使用匿名内部类。

什么是线程池?
(1)多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单 元的闲置时间,增加处理器单元的吞吐能力。
假设一个服务器完成一项任务所需时间为:T1—创建线程时间,T2—在线程中执行任务的时间,T3—销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:

  1. 线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池, 销毁线程池,添加新任务;
  2. 工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可 以循环的执行任务;
  3. 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行, 它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
  4. 任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。

线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性 能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的 时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一 个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完 成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程 的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般 线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000 而在处理请求时浪费时间,从而提高效率。

线程池的好处有哪些?
减少在创建和销毁线程上所花的时间以及系统资源的开销;
如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换”。

如何创建一个线程池,常用输入参数的含义?

  1. Executors.newCachedThreadPool()
    Executors.newCachedThreadPool(ThreadFactory threadFactory)
    newCachedThreadPool创建一个可缓存的线程池。
    这种类型的线程池特点是:
    1)工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。
    2)如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。
    3)参数threadFactory - 表示用来创建线程的线程工厂,在需要时使用提供的 ThreadFactory 创建新线程。

2.newFixedThreadPool(int nThreads)
newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
newFixedThreadPool创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。
参数nThreads - 表示池中的线程数。
参数threadFactory - 表示用来创建线程的线程工厂,在需要时使用提供的 ThreadFactory 创建新线程。

3.newSingleThreadExecutor()
newSingleThreadExecutor(ThreadFactory threadFactory)
newSingleThreadExecutor创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,如果这个线程异常结束,会有另一个取代它,保证顺序执行(我觉得这点是它的特色)。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。
参数threadFactory - 表示用来创建线程的线程工厂,在需要时使用提供的 ThreadFactory 创建新线程。

4.newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
newScheduleThreadPool创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer。
参数corePoolSize - 核心池的大小
参数threadFactory - 表示用来创建线程的线程工厂,在需要时使用提供的 ThreadFactory 创建新线程。

分析线程池的主要工作流程。
线程池的创建
向线程池提交任务
线程池关闭
在这里插入图片描述
当提交一个新任务到线程池时,线程池的处理流程如下:

  • 首先线程池判断“基本线程池”(corePoolSize)是否已满?没满,创建一个工作线程来执行任务。满了,则进入下个流程。
  • 其次线程池判断工作队列(workQueue)是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程。
  • 最后线程池判断整个线程池的线程数是否已超过maximumPoolSize?没满,则创建一个新的工作线程来执行任务,满了,则交给拒绝策略来处理这个任务。

如何监控线程池?
如果你想监控某一个线程池的执行状态,线程池执行类 ThreadPoolExecutor 也给出了相关的 API, 能实时获取线程池的当前活动线程数、正在排队中的线程数、已经执行完成的线程数、总线程数等

什么是设计模式?
设计模式是一套被反复使用的、多数人知晓、经过分类编目的优秀代码设计经验的总结。特定环境下特定问题的处理方法。
•重用设计和代码 重用设计比重用代码更有意义,自动带来代码重用
•提高扩展性 大量使用面向接口编程,预留扩展插槽,新的功能或特性很容易加入到系统中来。
•提高灵活性 通过组合提高灵活性,可允许代码修改平稳发生,对一处修改不会波及到其他模块。
•提高开发效率 正确使用设计模式,可以节省大量的时间。

设计模式的优点有哪些?

23 种经典设计模式都有哪些,如何分类?
在这里插入图片描述

面向对象的设计原则有哪些?
面向对象设计原则是面向对象设计的基石,面向对象设计质量的依据和保障,设计模式是面向对象设计原则的经典应用。
(1)单一职责原则 :SRP
(2)开闭原则:OCP
(3)里氏替代原则:LSP
(4)依赖注入原则:DIP
(5)接口分离原则:ISP
(6)迪米特原则:LOD
(7)组合/聚合复用原则:CARP
开闭原则具有理想主义色彩,它是面向对象设计的终极目标。其它设计原则都可以看作是开闭原则的实现手段或方法。

开闭原则的含义和实现
一个软件实体(如类,模块和函数)应该对扩展开放,对修改关闭。
开闭原则明确的告诉我们:软件实现应该对扩展开放,对修改关闭,其含义是说一个软件应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化的。
一个软件产品只要在生命周期内,都会发生变化,即然变化是一个事实,我们就应该在设计时尽量适应这些变化,以提高项目的稳定性和灵活性,真正实现“拥抱变化”。开闭原则告诉我们应尽量通过扩展软件实体的行为来实现变化,而不是通过修改现有代码来完成变化,它是为软件实体的未来事件而制定的对现行开发设计进行约束的一个原则。

依赖倒置原则的含义和实现
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
依赖倒置原则的核心思想是面向接口编程

结合 Java IO 流体系说明装饰模式
java中的IO流转换主要针对字节流向字符流的转换,字符流有行读写方法
在IO中,具体构件角色是节点流,装饰角色是过滤流。
1、继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit),如图,深色的为节点流,浅色的为过滤流。
在这里插入图片描述
2、继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit),如图,深色的为节点流,浅色的为过滤流。
在这里插入图片描述
从图中可以看出,InputStream就是装饰者模式中的超类(Component),ByteArrayInputStream,FileInputStream相当于被装饰者(ConcreteComponent),这些类都提供了最基本的字节读取功能。而另外一个和这两个类是同一级的类FilterInputStream即是装饰者(Decorator),BufferedInputStream,DataInputStream,PushbackInputStream…这些都是被装饰者装饰后形成的成品。为什么可以说:装饰模式可以在不创造更多子类的情况下,将对象的功能加以扩展,能理解这一点就能很好的掌握装饰者设计模式的精髓,如果在InputStream这里扩展出FilterInputStream类下面的装饰类,那么针对FileInputStream和ByteArrayInputStream就都要去实现一次BufferedInputStream了,那么可能就会衍生BufferedFileInputStream和BufferedByteArrayInputStream这样的类,如果按照这样的扩展方式去添加功能,对于添加功能的子类来说简直是一场噩梦,好在装饰着模式很好的解决了这个问题,现在我们只需要在过滤流类这里维护一个超类,不论传入的是什么具体的节点流,那么都只要套一层装饰,就能对功能方法进行加强。

结合 InputStreamReader 类说明适配器模式
适配器模式的功能很好的理解,就是把一个类的接口变换为客户端所能接收的另一种接口,从而使两个接口不匹配而无法在一起工作的两个类能够在一起工作。

适配器模式通常应用在一个项目需要引用一些开源框架来一起工作的情况下,这些框架的内部都有一些关于环境信息的接口,需要从外部传入,但是外部的接口不一定匹配,这种情况下就需要适配器模式来转换接口了。

适配器的作用就是将一个接口适配到另一个接口,在Java IO类库中有很多这样的需求,比如将字符串数据转化为字节数据保存在文件中,将字节数据转化为流数据等。下面以InputStreamReader和OutputStreamWriter为例介绍适配器模式。

InputStreamReader和OutputStreamWriter分别集成了Reader和Writer接口,创建他们的对象必须在构造函数中传入InputStream和OutputStream。InputStreamReader和OutputStreamWriter的作用就是将InputStream和OutputStream适配到Reader和Writer其中InputStreamReader的类图如下:
在这里插入图片描述
InputStreamReader实现了Reader接口,并持通过StreamDecoder间接持有InputStream的引用,因为从byte到char需要经过编码。

很显然适配器就是InputStreamReader,源角色是InputStream代表的实例对象,目标角色是Reader类,OutputStreamWriter也是类似的方式

请选择一个对你所熟悉的一个设计模式进行介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值