SE部分面试题汇总

1.Object类自带哪些方法?
1.clone()创建并返回此对象的副本
2.equals(Object obj)指示其它某个对象是否与此对象相等“地址相同”
3.finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法
4.getClass()返回此 Object 的运行时类
5.hashCode()返回该对象的哈希码值
6.notify()唤醒在此对象监视器上等待的单个线程
7.notifyAll()唤醒在此对象监视器上等待的所有线程
8.toString()返回该对象的字符串表示
9.wait()线程等待直至被唤醒,可传long类型时间参数

2.对String类了解多少
1.字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。
2.String 类包括的方法可用于检查序列的单个字符charAt(int)、比较字符串compareTo(String)、搜索字符串endsWith(String)startsWith(String)、提取子字符串subString(int,int)、创建字符串副本并将所有字符全部转换为大写或小写toUpperCase()toLowerCase()、将其它类型转换为string类型表示valueOf()、按指定编码方式编成byte数组getBytes(charset)。
3.Java 语言提供对字符串串联符号("+")。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过 toString 方法实现的

3.String、StringBuffer、StringBuilder的区别
1、String是字符串常量而StringBuffer和StringBuilde是字符串变量。
2、对于不同对象字符串的拼接,效率StringBuilder>StringBuffer>String,而其中StringBuilder是线程不安全的常用于单个线程的拼接,StringBuffer是线程安全的拼接。/
3、StringBuilder和StringBuffer主要方法有append和insert,append在字符串变量最后追加字符串,insert是在指定位置上添加字符
4、对String的了解参照第二问

4.collection和collections的区别
1、java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
2、Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序sort(List)、搜索以及线程安全等各种操作。注意:列表中的元素需实现 Comparable 以便进行其它操作

5.Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?
在JDK.API中这样描述set:set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素,所以用equals()方法来区分是否重复(拓展,==表示是否为同一对象,equals()方法表示引用对象是否相同)

6.从底层区分下ArrayList和LinkedList,Arraylist、LinkedList、HashMap的初始大小以及如何扩容
ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
1.List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素,当使用不带参数的构造方法生成ArrayList对象时,实际上会在底层生成一个长度为10的Object类型数组。每个 ArrayList 实例都有一个容量。该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。扩容后的大小= 原始大小*1.5
2.List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。没有初始化大小,也没有扩容的机制
3.基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。HashMap受两个参数影响:初始容量和加载因子。默认初始长度为16,对应的负载因子为0.75。

7.HashMap、Hashtable的区别
1、线程安全性不同:HashTable线程安全,HashMap线程不安全
2、key与value是否可为null:Hashtable中key和value都不允许出现null值,但是如果在Hashtable中有类似put(null,null)的操作,编译同样可以通过,因为key和value都是Object类型,但运行时会抛出NullPointerException异常。HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。因此也需通过containsKey()方法判断是否存在该键,因为get()方法返回的可能是value的空值也可能是键为null
3、哈希值不同:HashTable直接使用对象的hashCode。而HashMap重新计算hash值
4、继承父类不同:Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口
5、是否提供contains方法:HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因为contains方法容易让人引起误解。Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。
6、内部实现使用的数组初始化和扩容方式不同: HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。
Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。
Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。

8.HashMap的底层
HashMap底层是一个Entry数组,当发生hash冲突的时候,hashmap是采用链表的方式来解决的,在对应的数组位置存放链表的头结点。对链表而言,新加入的节点会从头结点加入。

9.HashMap、LinkedHashMap、ConcurrentHashMap的异同
HashMap查询和插入速度极快,但是线程不安全,在多线程情况下在扩容的情况下可能会形成闭环链路,耗光cpu资源。
LinkedHashMap基本和HashMap实现类似,多了一个链表来维护元素插入的顺序,因此维护的效率会比HashMap略低。但是因为有链表的存在,遍历效率会高于HashMap。
ConcurrentHashMap线程安全,而且采用分段锁的方式进行数据同步,因此相对于Hashtable来说,效率要高。但是因为引入了段的概念,所以每次元素插入或者获取,需要进行两次哈希算法,第一次确定到该元素位于哪一段,第二次才能真正确定到元素位置。因此效率会低于HashMap。不过在多线程情况下,这种性能的牺牲换取数据安全是非常值得的

10.Java中HashMap的key值要是为类对象,则该类需要满足什么条件?
1、需要重写equals()方法和hashCode()方法

11.Comparable和Comparator接口是干什么的?列出它们的区别。
Comparable & Comparator 都是用来实现集合中元素的比较、排序的。
1、排序实现: Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序。
2、Comparator位于包java.util下,而Comparable位于包 java.lang下。在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序, 这里的自然顺序就是实现Comparable接口设定的排序方式。 而 Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
两种方式,各有各的特点:使用Comparable方式比较时,我们将比较的规则写入了比较的类型中,其特点是高内聚。但如果哪天这个规则需要修改,那么我们必须修改这个类型的源代码。如果使用Comparator方式比较,那么我们不需要修改比较的类,其特点是易维护,但需要自定义一个比较器,后续比较规则的修改,仅仅是改这个比较器中的代码即可。

12.什么是流?按照传输的单位,分成哪两种流?他们的父类叫什么?
1、用于处理数据的传输的过程叫做流,
三种分类方式:1.按流的方向分为:输入流和输出流
2.按流的数据单位不同分为:字节流和字符流
3.按流的功能不同分为:节点流和处理流
2、按照传输单位可分为字节流和字符流
3、字节流的顶级超类InputStream和OutputStream
字符流的超类FileReader和FileWriter继承顶级超类Reader和Writer

13.什么叫对象序列化,什么是反序列化,如何实现对象序列化
把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
对象序列化包括如下步骤:
  1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
  2) 通过对象输出流的writeObject()方法写对象。

对象反序列化的步骤如下:
  1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
  2) 通过对象输入流的readObject()方法读取对象。

14.开启线程的三种方式
1、自定义线程类,继承Thread类,新建当前类对象,重写run()方法,并且用start()方法开启
2、自定义类,实现Runnable接口,然后新建当前类对象,接着新建Thread对象时把当前类对象作为参数传进去,最后运行Thread对象的start()方法
3、方式三、实现Callable接口

15.进程,线程,协程之间的区别
 1、进程
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。
  2、线程
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
  3、协程
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
区别:
  1、进程多与线程比较
线程是指进程内的一个执行单元,也是进程内的可调度实体。线程与进程的区别:

  1. 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间
  2. 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
  3. 线程是处理器调度的基本单位,但进程不是
  4. 二者均可并发执行
  5. 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
      2、协程多与线程进行比较
  6. 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。
  7. 线程进程都是同步机制,而协程则是异步
  8. 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

16.线程之间是如何通信的
利用等待唤醒机制:(wait()、notify())
  就是在一个线程进行了规定操作后,就进入等待状态(wait), 等待其他线程执行完他们的指定代码过后 再将其唤醒(notify);

17.在Java中sleep和wait方法的不同
1、这两个方法来自不同的类分别是Thread和Object
2、最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法(锁代码块和方法锁)。
3、 wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)
4、sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
5、sleep方法属于Thread类中方法,表示让一个线程进入睡眠状态,等待一定的时间之后,自动醒来进入到可运行状态,不会马上进入运行状态,因为线程调度机制恢复线程的运行也需要时间,一个线程对象调用了sleep方法之后,并不会释放他所持有的所有对象锁,所以也就不会影响其他进程对象的运行。但在sleep的过程中有可能被其他对象调用它的interrupt(),产生InterruptedException异常,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。
6、注意sleep()方法是一个静态方法,也就是说他只对当前对象有效,通过t.sleep()让t对象进入sleep,这样的做法是错误的,它只会是使当前线程被sleep 而不是t线程
7、 wait属于Object的成员方法,一旦一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程;如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了wait()方法的对象。wait()方法也同样会在wait的过程中有可能被其他对象调用interrupt()方法而产生

18.谈谈ThreadLocal关键字
ThreadLocal并非一个线程,而是一个线程局部变量。它的作用就是为使用该变量的线程都提供一个变量值的副本,每个线程都可以独立的改变自己的副本,而不会和其他线程的副本造成冲突。
get()方法用于获取当前线程的副本变量值。
set()方法用于保存当前线程的副本变量值。
initialValue()为当前线程初始副本变量值。
remove()方法移除当前前程的副本变量值。

通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制。
对于多线程资源的共享,ThreadLocal采用了“以空间换时间”的方式,为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

19.run()和start()方法区别
调用线程的start()方法是创建了新的线程,在新的线程中执行。
调用线程的run()方法是在主线程中执行该方法,和调用普通方法一样
]

20.什么是线程池,为什么要用线程池,说出几种常见的线程池
一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。线程池不仅能够保证内核的充分利用,还能防止过分调度。

  1. 每次new Thread新建对象性能差。
  2. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
  3. 缺乏更多功能,如定时执行、定期执行、线程中断。相比new Thread,Java提供的四种线程池的好处在于:
  4. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
  5. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  6. 提供定时执行、定期执行、单线程、并发数控制等功能。
    ①newSingleThreadExecutor
    单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务
    ②newFixedThreadExecutor(n)
    固定数量的线程池,每提交一个任务就是一个线程,直到达到线程池的最大数量,然后后面进入等待队列直到前面的任务完成才继续执行
    ③newCacheThreadExecutor(推荐使用)
    可缓存线程池,当线程池大小超过了处理任务所需的线程,那么就会回收部分空闲(一般是60秒无执行)的线程,当有任务来时,又智能的添加新线程来执行。
    ④newScheduleThreadExecutor
    大小无限制的线程池,支持定时和周期性的执行线程

21.描述一下线程的生命周期(描述5个状态)

线程可以分为4个状态:
New(新生),
Runnable(可运行):为了方便分析,还可将其分为:Runnable与Running。
blocked(被阻塞),
Dead(死亡)。

22.为什么会发生死锁,如何避免死锁
死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所占用不会释放的资源而处于的一种永久等待状态。
死锁产生的四个必要条件
1、互斥使用(即当资源被一个线程使用(占有)时,别的线程不能使用 )
2、不可抢占(资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放)
3、请求和保持(即当资源请求者在请求其他的资源的同时保持对原有资源的占有)
4、循环等待(即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路)
通过破坏产生死锁的四个必要条件,预防死锁,而由于资源互斥是资源使用的固有特性是无法改变的,因此破坏另外三个条件:
破坏“不可剥夺”条件:一个进程不能获得所需要的全部资源时便处于等待状态,等待期间他占有的资源将被隐式的释放重新加入到 系统的资源列表中,可以被其他的进程使用,而等待的进程只有重新获得自己原有的资源以及新申请的资源才可以重新启动,执行。
破坏”请求与保持条件“:第一种方法静态分配即每个进程在开始执行时就申请他所需要的全部资源。第二种是动态分配即每个进程在申请所需要的资源时他本身不占用系统资源。
破坏“循环等待”条件:采用资源有序分配其基本思想是将系统中的所有资源顺序编号,将紧缺的,稀少的采用较大的编号,在申请资源时必须按照编号的顺序进行,一个进程只有获得较小编号的进程才能申请较大编号的进程。

23.多线程中的锁有哪些种类,说下区别
一、公平锁/非公平锁(是否按照申请顺序获得锁)
二、独享锁/共享锁(是否能被多个线程持有)
三、互斥锁(保护共享资源)/读写锁(保护资源访问)
四、乐观锁/悲观锁(是否在同一个数据的并发操作上加锁)
五、偏向锁(一段同步代码一直被一个线程所访问,自动获取锁)/轻量级锁(锁是偏向锁的时候,被另一个线程所访问)/重量级锁(锁为轻量级锁的时候,另一个线程虽然是自旋,在一定次数后依然未获取锁,就会进入阻塞,该锁膨胀为重量级锁)【锁的状态】
六、自旋锁(指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁)

24.Synchronized和Lock锁的区别

1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

25.Synchronized有什么缺陷
1、无法控制阻塞时长 2、阻塞不可中断
那么如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能等待

26.并行与并发的异同
并发:多个线程同时都处在运行中的状态。线程之间相互干扰,存在竞争,(CPU,缓冲区),每个线程轮流使用CPU,当一个线程占有CPU时,其他线程处于挂起状态,各线程断续推进。
并行:多个线程同时执行,但是每个线程各自有自己的CPU,不存在CPU资源的竞争,他们之间也可能存在资源的竞争。
并发发生在同一段时间间隔内,并行发生在同一时刻内。并发执行的总时间是每个任务的时间和,而并行则取决于最长任务的时间。

27.Java如何实现并发
Synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。Synchronized的作用主要有三个:(1)确保线程互斥的访问同步代码(2)保证共享变量的修改能够及时可见(3)有效解决重排序问题。从语法上讲,Synchronized总共有三种用法:
  (1)修饰普通方法
  (2)修饰静态方法
(3)修饰代码块
同步方法:同步方法锁定的是当前对象。当多线程通过同一个对象引用多次调用当前同步方法时, 需同步执行。
同步代码块:同步代码块的同步粒度更加细致,是商业开发中推荐的编程方式。可以定位到具体的同步位置,而不是简单的将方法整体实现同步逻辑。在效率上,相对更高。
使用悲观锁、乐观锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值