推荐学习:https://study.163.com/course/courseMain.htm?courseId=1208983820

1.Collection和Collections的区别

图片.pngCollection是集合类的上级接口,继承与他有关的接口主要有List和Set

Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全等操作

稍微举个例子:

java代码

public static void main(String args[]) {
//注意List是实现Collection接口的
List list = new ArrayList();
double array[] = { 112, 111, 23, 456, 231 };
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
Collections.sort(list); //把list按从小到大排序
for (int i = 0; i < array.length; i++) {
System.out.println(list.get(i));
}
// 结果:23.0 111.0 112.0 231.0 456.0
}

然后还有混排(Shuffling)、反转(Reverse)、替换所有的元素(fill)、拷贝(copy)、返回Collections中最小元素(min)、返回Collections中最大元素(max)、返回指定源列表中最后一次出现指定目标列表的起始位置(lastIndexOfSubList)、返回指定源列表中第一次出现指定目标列表的起始位置(IndexOfSubList)、根据指定的距离循环移动指定列表中的元素(Rotate)

2.Hashmap底层怎么实现?


HashMap存储过程底层实现:
HashSet的存储过程->HashMap的存储过程
1.hashCode()计算位置
2.位置上如果没有元素,直接加入
3.位置上如果有元素,用equals方法判断是否相等
若相等,不添加
若不相等,位置上链表的每一个节点判断不想等,添加到链表末尾
因为链表的访问效率非常低,所以要尽量使每个位置上的链表长度要短一些,这就要求HashMap的容量要大,但是考虑到空间的使用率,容量不可无限增大,jdk默认初始容量是16

如果后期的数据量太大,需要扩容,不能等到存满了再扩容
扩容实现:容量改变,原来集合中的对象复制到新扩容的集合里面,需要重新计算位置
需要消耗时间,所以不可频繁的扩容
综合考虑,当集合存储到75%时,扩容一倍
结论:HashMap初始容量16 加载因子0.75

3..coucurrenthashmap原理

4.ArrayList线程安全吗?有哪些线程安全的数据结构。

ArrayList 是线程不安全的,
线程安全:Vector、ConcurrentHashMap、ConcurrentLinkedQueue、ConcurrentLinkedHashMap、ConcurrentSkipListMap.

5.Java中线程安全的类有哪些?

6.进程和线程的区别

  • 进程是资源分配的最小单位,线程是程序执行的最小单位。
  • 进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
  • 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
  • 但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
  • 线程是栈分配的最小单元,其每个线程有两个栈,一个是在调用内核函数时候的内核态的栈,和用户态的栈,主要是安全方面考虑,防止用户态的通过栈指针访问到内核的数据。
  • 操作系统为每个线程栈的分配的空间有大小限制,所以在使用栈的时候,要防止函数栈的溢出(不要申请大数组),损坏栈区的数据。

7.进程之间的通信、线程之间的通信


一、进程间的通信方式

1.管道( pipe ):
管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
2.有名管道 (namedpipe) :
有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
3.信号量(semophore ) :
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
4.消息队列( messagequeue ) :
消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
5.信号 (sinal ) :
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
6.共享内存(shared memory ) :
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
7.套接字(socket ) :
套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同设备及其间的进程通信。
二、线程间的通信方式

1.锁机制:包括互斥锁、条件变量、读写锁
互斥锁提供了以排他方式防止数据结构被并发修改的方法。
读写锁允许多个线程同时读共享数据,而对写操作是互斥的。
条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
2.信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
3.信号机制(Signal):类似进程间的信号处理
线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。

8.一个线程的生命周期


线程的生命周期包含5个阶段,包括:新建、就绪、运行、阻塞、销毁。

  • 新建:就是刚使用new方法,new出来的线程;
  • 就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;
  • 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;
  • 阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态;
  • 销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;

    9.线程池怎么实现?


    https://baijiahao.baidu.com/s?id=1641469444994560637&wfr=spider&for=pc

    10.乐观锁和悲观锁的Java中的体现


    java中较为常用的锁是synchronized和ReentrantLock,实际上这两种锁都是悲观锁,悲观锁就是一般的锁,java并不强调悲观和乐观的概念。在java并发里悲观和乐观的区分不如说是上锁和Ad-hoc线程封闭的区别。通俗的理解,悲观就是用锁控制多线程访问,乐观更多的是用程序本身的规则约束数据不能被错误的访问到。
    如何在java中实现乐观锁?回到乐观锁的概念,用版本来控制数据不被错误的访问。在你的java程序中添加int活着double型的version字段,但是你要确保版本的访问和最后数据的修改锁是被锁保护的,这样做大概采用了乐观锁的概念,能够起到的效果是减少了临界区的范围,如果你的事务很长,采用这种方法尚可。不要在不能使用乐观锁的地方强行使用乐观锁,它的概念不是为java而生的而是数据库。不要弄巧成拙。

    11.equals和==的区别

“==”比如你在一个类中定义了两个个String基本类型的变量,那么这两个变量是的值相等则用“==”比较的值为真
但是如果你通过引用String类型定义一个值相同的变量再与之前基本类型用“==”比较的值为假
这是因为引用类型还需要比较引用的地址。
equals本质是==,但是可以比较引用类型和基础类型的值为真,而不会去比较其引用的地址,但是如果是自定义的类则还需要比较引用的类型。

12.sychronized和lock的区别


https://blog.csdn.net/qq_33666602/article/details/89294106

13.Socket通信是怎么建立的?


socket通信:

这也是面试常见的问题,面试者最起码要知道基本流程:

服务器:

1.创建一个socket

2.bind一个句柄(端口和地址)

3.listen设置监听的客户数

4.accept客户端的句柄

5.读写。

客户机:

1.创建一个socket

2.connect到服务器
3.读写操作。
socket通信又会涉及到阻塞和非阻塞的方式。

14.序列化和反序列化


把对象转换为字节序列的过程称为对象的序列化
把字节序列恢复成对象的过程称为对象的反序列化

一、对象的序列化的应用:
1.把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中。
2.在网络上传送对象的字节序列
当大量用户并发访问网站时,Web服务器中会产生大量Session对象,这样会占用大量内存。因此Web服务器会将一些Session对象先进行序列化并保存在硬盘里,需要用时再还原到内存中来。

1、JDK类库中序列化和反序列化API
(1)java.io.ObjectOutputStream:表示对象输出流;
它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中;
(2)java.io.ObjectInputStream:表示对象输入流;
它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回;

15.动态代理和静态代理的区别


按照代理的创建时期,代理类可以分为两种:
静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态:在程序运行时运用反射机制动态创建而成
https://www.cnblogs.com/shan1393/p/9044143.html

16.消息队列

17.自动拆箱


https://www.cnblogs.com/kangxinxin/p/9689701.html

18.双亲委派模型