Java基本知识点回顾二
2022/4/6 1:19:21
本文主要是介绍Java基本知识点回顾二,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1、字节流和字符流的区别
字节流读取的时候,读到一个字节就返回一个字节;字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在utf-8码表中是三个字节)时,先去查指定的编码表,将查到的字符返回。字节流可以处理所有类型数据,如:图片、MP3,AVI视频文件,而字符流只能处理字符数据,只要是处理纯文本数据,就要优先考虑使用字符流,除此之外都用字节流,字节流主要是操作byte类型数据,以byte数组为准,主要操作类就是OutputStream、InputStream。
字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组,所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单元的字符而成的,所以它对多国语言支持性比较好。
2、System.arrayCopy是浅拷贝还是深拷贝
结论是浅拷贝,引用类型是复制其引用。建议可以自己写一个方法验证(可参考:https://blog.csdn.net/qq_35152037/article/details/84235894)
3、Comparator与Comparable的区别
Comparable接口实际上是出自java.lang包,它有一个compareTo(Object obj)方法用来排序。
Comparator接口实际上是出自java.util包,它有一个compare(Object obj1,Object obj2)方法用来排序。
⼀般我们需要对⼀个集合使⽤⾃定义排序时,我们就要重写 compareTo() ⽅法或 compare() ⽅法,当我们需要对某⼀个集合实现两种排序⽅式,⽐如⼀个song对象中的歌名和歌⼿名分别采⽤⼀种排序⽅法的话,我们可以重写 compareTo() ⽅法和使⽤⾃制的Comparator⽅法或者以两个Comparator来实现歌名排序和歌星名排序,第⼆种代表我们只能使⽤两个参数版的 Collections.sort()。
(以上内容来自JavaGuide面试突击版文档)
个人总结:两个比较明显的区别是如果我们要比较的实体类是来自第三方包,然后我们又不能去改动对应的实体类,也就是说我们不能给这个类添加Comparable接口的话,那么在排序的时候我们就得去写一个比较器,也就是Comparator。
4、进程与线程定义
进程:进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的,系统运行一个程序即是一个进程从创建,运行到消亡的过程。在Java中,当我们启动main函数时其实就是启动一个JVM的进程,而main函数所在的线程就是这个进程中的一个线程,也称主线程。
线程:线程与进程相似,但线程是一个比进程更小的执行单位,一个进程在其执行的过程中可以以产生多个线程,与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
5、产生死锁的条件
1)互斥条件:该资源任意一个时刻只由一个线程占用
2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
3)不剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源
4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
6、如何避免线程死锁
如何避免死锁的话,我们可以从死锁的四个产生条件去入手
1)破坏互斥条件:这个条件没法破坏,因为我们用锁本来就是想让他们互斥(临界资源需要互斥访问)
2)破坏请求与保持条件:一次性申请所有的资源
3)破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占用的资源。
4)破坏循环等待条件:靠按序申请资源来预防,按某一顺序申请资源,释放资源则反序释放,破坏循环等待条件。
7、单例模式的双重校验锁实现
public class Singleton { private volatile static Singleton instance; private Singleton(){ } public static Singleton getInstance(){ if(instance == null){ synchronized(Singleton.class){ if(instance == null){ instance = new Singleton(); } } } return instance; } }
这里为什么要加volatile关键字呢?因为new Singleton()这段代码其实是分三步执行
1)为instance分配内存空间
2)初始化instance
3)将instance指向分配的内存地址
但由于JVM具有指令重拍的特性,所以顺序有可能变成1—》3——》2,指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例,例如,线程T1执行了1和3,此时T2调用getInstance()后发现instance不为空,因此返回instance,但此时instance还未被初始化。
还有一个问题就是这里为什么不在静态方法加synchronized关键字呢?理由是因为加在静态方法的话,锁粒度太大,在高并发的情况下,例如有100个线程,有一个线程获取了这个锁话,后面99个都得等待前面那个线程释放锁;但如果我们只把synchronized加在方法里面的话,多线程的情况下,其实只有一开始初始化的时候,多个线程需要等待,而在初始化成功后,多线程获取单例则可以直接获取到,因为instance不为空了,所以不会走到synchronized的代码行那里了。
8、synchronized关键字和volatile关键字的区别
1)volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好,但是volatile关键字只能用于变量而synchronized关键字可以修饰方法和代码块
2)多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞。
3)volatile关键字能保证数据的可见性,但不能保证数据的原子性,synchronized关键字两者都能保证。
4)volatile关键字主要用于解决变量在多个线程之间的可见性,而synchronized关键字解决的是多个线程之间访问资源的同步性。
9、ThreadLocal是什么
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的,如果想实现每一个线程都有自己的专属本地变量该如何解决呢?JDK中提供的ThreadLocal类正是为了解决这样的问题。
ThreadLocal类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。
如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是ThreadLocal变量名的由来,他们可以使用get()和set()方法来获取默认值或将其值更改为当前线程所存的副本的值,从而避免了线程安全问题。
这篇关于Java基本知识点回顾二的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-15鸿蒙生态设备数量超8亿台
- 2024-05-13TiDB + ES:转转业财系统亿级数据存储优化实践
- 2024-05-09“2024鸿蒙零基础快速实战-仿抖音App开发(ArkTS版)”实战课程已上线
- 2024-05-09聊聊如何通过arthas-tunnel-server来远程管理所有需要arthas监控的应用
- 2024-05-09log4j2这么配就对了
- 2024-05-09nginx修改Content-Type
- 2024-05-09Redis多数据源,看这篇就够了
- 2024-05-09Google Chrome驱动程序 124.0.6367.62(正式版本)去哪下载?
- 2024-05-09有没有大佬知道这种数据应该怎么抓取呀?
- 2024-05-09这种运行结果里的10.100000001,怎么能最快改成10.1?