Java·JVM·JUC(二)
Java·JVM·JUC(二)
实现单例设计模式(懒汉,饿汉)
单例模式的三大特性
- 单例类只有一个实例。
- 单例类必须自己实例化自己。
- 单例类需要向外提供实例。
饿汉模式(立即加载)
立即加载就是使用类的时候已经将对象创建完毕
public class Singleton { |
懒汉模式(延迟加载)
public class Singleton { |
懒汉模式-线程安全
public class Singleton { |
DCL双检查锁机制
需要用到关键字volatile,防止指令重排。如果不用volatile关键字,就会和线程不安全情形一样,在if判断那会有并发。
class Singleton { //双重检查 |
静态内部类
class Singleton { |
枚举
enum Singleton { |
== 和 equals() 的区别?
== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
public class test1 { |
线程池是如何实现的?简述线程池的任务策略
线程池如何实现
假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:
线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。任务队列的实现可以是一个简单的ArrayDeque 双端队列,其核心方法是对任务的取出与暂存操作,当需要取出一个任务时,必须进行非空判断,可以通过添加锁机制,例如Reetrantlock来实现锁空队列,当任务被暂存时,通过Condition条件唤醒需要取出任务的线程继续执行任务,从而实现类似生产者与消费者之间的平衡关系。
任务调度
任务暂存
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
任务拒绝
任务拒绝模块是线程池的保护部分,线程池有一个最大的容量,当线程池的任务缓存队列已满,并且线程池中的线程数目达到maximumPoolSize时,就需要拒绝掉该任务,采取任务拒绝策略,保护线程池。
public interface RejectedExecutionHandler { |
worker工作线程
线程池的工作线程worker实现了Runnable类
简述 Java 的反射机制及其应用场景
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为Java的反射机制。
应用场景
①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;
②Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:
将程序内所有 XML 或 Properties 配置文件加载入内存中;
Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息;
使用反射机制,根据这个字符串获得某个类的Class实例;
动态配置实例的属性
简述 Spring AOP 的原理
AOP(Aspect Oriented Programming)是基于切面编程的,可无侵入的在原本功能的切面层添加自定义代码,一般用于日志收集、权限认证等场景。减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
- Jointpoint(连接点):具体的切面点点抽象概念,可以是在字段、方法上,Spring中具体表现形式是PointCut(切入点),仅作用在方法上。
- Advice(通知): 在连接点进行的具体操作,如何进行增强处理的,分为前置、后置、异常、最终、环绕五种情况。
- 目标对象:被AOP框架进行增强处理的对象,也被称为被增强的对象。
- AOP代理:AOP框架创建的对象,简单的说,代理就是对目标对象的加强。Spring中的AOP代理可以是JDK动态代理,也可以是CGLIB代理。
- Weaving(织入):将增强处理添加到目标对象中,创建一个被增强的对象的过程
总结为一句话就是:在目标对象(target object)的某些方法(jointpoint)添加不同种类的操作(通知、增强操处理),最后通过某些方法(weaving、织入操作)实现一个新的代理目标对象。
JVM 内存是如何对应到操作系统内存的?
原来jvm的设计的模型其实就是操作系统的模型,基于操作系统的角度,jvm就是个该死的java.exe/javaw.exe,也就是一个应用,而基于class文件来说,jvm就是个操作系统,而jvm的方法区,也就相当于操作系统的硬盘区,所以你知道我为什么喜欢叫他permanent区吗,因为这个单词是永久的意思,也就是永久区,我们的磁盘就是不断电的永久区嘛,是一样的意思啊,多好对应啊。而java栈和操作系统栈是一致的,无论是生长方向还是管理的方式,至于堆嘛,虽然概念上一致目标也一致,分配内存的方式也一直(new,或者malloc等等),但是由于他们的管理方式不同,jvm是gc回收,而操作系统是程序员手动释放
简述 Spring bean 的生命周期
Java 中接口和抽象类的区别
相同点
- 接口和抽象类都不能被实例化,主要用于被其他类实现和继承。
- 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
不同点
String,StringBuffer,StringBuilder 之间有什么区别?
- 可变性
String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。
- 线程安全性
String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。
- 以下源码中也可以看出就是多了一个synchronized 的区别
public final class StringBuffer |
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, Appendable, CharSequence { |
- 性能
每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
使用范围
如果要操作少量的数据用 ————————-String
单线程操作字符串缓冲区 下操作大量数据—StringBuilder
多线程操作字符串缓冲区 下操作大量数据—StringBuffer
题目答案均为转载,题目先后顺序按各大厂总出题次数排列!