基础
基础模块
JDK和JRE的区别
-
jdk
- java develpment kit(java开发工具包),提供了java的开发环境和运行环境
-
jre
- java runtime environment的简称,java运行环境,为java运行提供了需要的环境
== 和 equals 的区别
-
==
- 对于基本类型和引用类型 == 的作用效果是不同的
基本类型:比较的是值是否相同
引用类型:比较的是引用是否相同
- 对于基本类型和引用类型 == 的作用效果是不同的
-
equals
- equals 本质上就是 == 只不过String和 Integer 重写了equals方法,把它变成了值比较
两个对象的hashcode() 相同,则equals 一定为true吗?
- 不对,两个对象的hashcode相同,equals不一定为true
final在java中的作用
- final修饰类叫做最终类,该类不能被继承。
- final修饰方法不能背重写
- final修饰变量叫常量,常量必须初始化,初始化之后不能被修改
java 中的 Math.round(-1.5) 等于多少?
- 等于 -1
String属于基础数据类型吗?
-
不属于,属于对象
-
基本数据类型
- byte
- boolean
- char
- short
- int
- long
- double
-
java中操作字符串都有哪些
-
String
-
不可变对象
- 所以在经常改变字符串内容的情况下最好不要使用
-
-
StringBuffer
-
可以在原对象基础上去操作
- 线程安全
-
-
StringBuilder
-
可以在原对象基础上去操作
- 线程不安全
-
String str="i"与 String str=new String(“i”)一样吗?
- 不一样,String i = “i”,java虚拟机将分配到常量池中,而String str = new String(”i“)则会被分到堆内存中
如何将字符串翻转
-
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。
- // StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(“abcdefg”);
System.out.println(stringBuffer.reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(“abcdefg”);
System.out.println(stringBuilder.reverse()); // gfedcba
- // StringBuffer reverse
String类常用方法
-
indexOf
- 返回指定字符索引值
-
charAt
- 返回指定索引处的字符
-
replace
- 字符串替换
-
trim
- 去除字符串两端空白
-
split
- 分割字符串,返回一个分割后的字符串数组
-
getBytes
- 返回字符串的byte类型数组
-
length
- 返回字符串长度
-
toLowerCase
- 将字符串转换成小写字母
-
toUpperCase
- 将字符串转换成大写字母
-
substring
- 截取字符串
-
equals
- 字符串比较
抽象类必须要用抽象方法吗?
-
不需要
- abstract class Cat {
public static void sayHi() {
System.out.println(“hi~”);
}
}
- abstract class Cat {
普通类和抽象类的区别
- 不同类不能包含抽象方法,抽象类可以包含抽象方法
- 抽象类不能直接实例化,普通类可以直接实例化
抽象类可以使用final 修饰吗?
- 不能,定义抽象类就是为了让其他类去继承,如果定义了final该类就不能被继承,这样彼此之间就产生了矛盾
接口和抽象类的区别?
-
实现
- 抽象类使用的extends 来继承,接口使用implements来实现
-
构造函数
- 抽象类可以有构造函数,接口不能有
-
main方法
- 抽象类中可以有main方法,接口中不能有main方法
-
实现数量
- 类可有多了接口,但只能继承一个对象
-
访问修饰符
- 接口中方法默认使用public修饰,抽象类中方法可以是任意修饰符
java中IO流分为几种
-
功能
- 输入流、输出流
-
类型
- 字节流、字符流
-
字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。
FIles常用的方法有哪些
-
FIles.exists()
- 检测文件是否存在
-
FIles.createFile()
- 创建文件
-
Files.createDiretory()
- 创建文件夹
-
Files.delete()
- 删除一个文件或者目录
-
Files.copy()
- 复制文件
-
Files.move()
- 移动文件
-
Files.size()
- 文件个数
-
Files.read()
- 读取文件
-
FIles.write()
- 写入文件
FIle
- exists():判断File对象代表的文件或者目录是否已经存在
*. File对象既可以代表已经存在的文件
又可以代表当前尚不存在的文件 - isFile():判断File对象代表的是不是一个文件
- isDirectory():判断File对象代表的是不是一个目录
- length(): 得到文件的字数个数(文件大小)
- delete(): 删除文件或者目录
- mkdirs(): 创建多层不存在的目录结构
- renameTo() : 重命名文件或者目录
- getName(): 得到文件或者目录的名字
- getParent(): 得到文件或者目录的父目录
- getAbsolutePath(): 得到文件或者目录的绝对路径
- setLastModified() : 设置文件最后一次的修改时间
- lastModified(): 得到文件最后一次的修改时间
容器
java容器目录
-
Collection [kəˈlekʃn]
-
List
- Vector [ˈvektə®]
- ArrayList
- LinkedList 林特
-
Queue [kjuː]
- LinkedList
- PriorityQueue
-
Set
-
HashSet
- LinkHashSet
-
TreeSet
-
-
-
Map
- HashMap
- TreeMap
Collection 和 Collections
-
Collection
- java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
-
Collections
- Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
List、Set、Map的区别
-
List
-
继承接口
- Collection
-
常用实现类
- ArrayList、LinkedList、Vector
-
常用方法
- add、remove、clear、get、contains(当前列表若包含某元素,返回结果为true, 若不包含该元素,返回结果为false)、size
-
元素
- 可重复
-
顺序
- 有序
-
线程安全
- Vector 线程安全
-
-
Set
-
继承接口
- Collection
-
常用实现类
- HashSet、LinkedHashSet、TreeSet
-
常用方法
- add、remove、clear、contains(当前列表若包含某元素,返回结果为true, 若不包含该元素,返回结果为false)、size
-
元素
- 不可重复 .equals()
-
顺序
- 无序 由HashCode决定
-
线程安全
- 无
-
-
Map
-
继承接口
- 无
-
常用实现类
- HashMap、HashTable
-
常用方法
- put()、get()、remove()、clear()、 containsKey() --(有key和value键值对,就会有判断是否有key)、 containsValues–(有key和value键值对,就会有判断是否有value)、 KeySet返回此映射中包含的键的 Set 视图 将map中所有的键存入到Set集合、 values()输出所有的值 、size()
-
元素
- 不可重复
-
顺序
-
线程安全
- HashTable线程安全
-
HashMap 和 Hashtable 有什么区别?
- hashMap 去掉了hashtable中的contains方法,但加上了containsValue 和 containsKey方法 kənˈteɪnz
- hashTable是同步的,hashmap是非同步的,效率上比hashtable要高
- hashMap允许空值,HashTable中不允许
如何决定使用 HashMap 还是 TreeMap?
- 对于Map中插入、删除和定位元素这类操作,hashmap是最好我的选择,然而假如需要对一个有序的key集合遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。
如何实现数组和 List 之间的转换?
- List转换成为数组:调用ArrayList的toArray方法。
- 数组转换成为List:调用Arrays的asList方法。
说一下 HashMap 的实现原理?
- HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
HashMap的数据结构: 在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。
当我们往Hashmap中put元素时,首先根据key的hashcode重新计算hash值,根绝hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾.如果数组中该位置没有元素,就直接将该元素放到数组的该位置上。
需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)
说一下 HashSet 的实现原理?
- HashSet底层由HashMap实现
HashSet的值存放于HashMap的key上
HashMap的value统一为PRESENT
ArrayList 和 LinkedList 的区别是什么?
- 最明显的区别是 ArrrayList底层的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构是双向循环链表,不支持随机访问。使用下标访问一个元素,ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)。
ArrayList 和 Vector 的区别是什么?
- Vector是同步的,而ArrayList不是。然而,如果你寻求在迭代的时候对列表进行改变,你应该使用CopyOnWriteArrayList。
- ArrayList比Vector快,它因为有同步,不会过载。
- ArrayList更加通用,因为我们可以使用Collections工具类轻易地获取同步列表和只读列表。
Array 和 ArrayList 有何区别?
- Array可以容纳基本类型和对象,而ArrayList只能容纳对象。
- Array是指定大小后不可变的,而ArrayList大小是可变的。
- Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。
在 Queue 中 poll()和 remove()有什么区别?
- poll() 和 remove() 都是从队列中取出一个元素,但是 poll() 在获取元素失败的时候会返回空,但是 remove() 失败的时候会抛出异常。
那些集合是线程安全的
- vector
- hashtable
- statck
- enumeration
迭代器 Iterator 是什么?
- 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
Iterator 怎么使用?有什么特点?
- 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
- 使用next()获得序列中的下一个元素。
- 使用hasNext()检查序列中是否还有元素。
- 使用remove()将迭代器新返回的元素删除。
- Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
Iterator 和 ListIterator 有什么区别?
- Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
- Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
- ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
反射
什么是反射
-
反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力
- 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法
- Java反射机制主要提供了以下功能:
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法。
什么是java序列化
- 简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保存object states,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。
什么情况下需要序列化:
- a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;
动态代理是什么?有哪些应用
- 当想要给实现了某个接口的类中的方法,加一些额外的处理。比如说加日志,加事务等。可以给这个类创建一个代理,故名思议就是创建一个新的类,这个类不仅包含原来类方法的功能,而且还在原来的基础上添加了额外处理的新类。这个代理类并不是定义好的,是动态生成的。具有解耦意义,灵活,扩展性强。
动代理的应用:
Spring的AOP
加事务
加权限
加日志
怎么实现动态代理
- 首先必须定义一个接口,还要有一个InvocationHandler(将实现接口的类的对象传递给它)处理类。再有一个工具类Proxy(习惯性将其称为代理类,因为调用他的newInstance()可以产生代理对象,其实他只是一个产生代理对象的工具类)。利用到InvocationHandler,拼接代理类源码,将其编译生成代理类的二进制码,利用加载器加载,并将其实例化产生代理对象,最后返回。
多线程
并行和并发有什么区别
- 并行是指两个或者多个事件在同一时刻发生,而并发是指两个或者多个事件在同一时间间隔发生
- 并行是在不同实体上的多个事件,而并发是在同一实体上的多个事件
- 在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。
线程和进程的区别
- 进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程。进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源。减小切换次数,从而效率更高。线程的进程是一个实体,是cpu调度和分配的基本单位,是比程序更小的能独立运行的基本单位。同一进程中的多个线程之间可以并发执行
守护线程是什么
- 守护线程(daemon thread),是一个服务线程,准确的说就是服务其他线程的线程,优先级最低
创建线程的方式
-
继承Thread类创建线程
- 定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务 因此吧run方法称为执行体
- 创建了Thread子类的实例,即创建了线程对象.
- 调用线程的start()方法即启动了该线程
-
通过Runnable接口创建线程类
- 定义runnable接口实现类,并重写run()方法,该run方法的方法体同样的线程的执行体
- 创建Runnable实现类的实例,并依此实例作为Thread的target来创建,该thread才是真正的线程对象
- 调用线程对象的start方法来启动线程
-
通过Callable和Future创建线程
- 创建Callable接口实现类,并实现call方法,该call方法将作线程的执行体,并有返回值
- 创建Callable实现类的实例,使用FutureTask类包装Callable对象,该FutureTask对象封装了该Callbale对象的的call方法的返回值
- 使用FutureTask对象作为Thread对象的target创建并启动新线程。
- 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
runnable和callable有什么区别
- runnable接口中的run方法的返回值为void,他做的事情只是纯粹的去执行run方法中的代码而已
- callable接口中的call方法是友返回值的,是一个泛型,和Future FuturnTask配合可以用来捕获异步执行的结果
线程有哪些状态
-
创建
- 在生成线程对象,并没有调用start方法,这时线程处于创建状态
-
就绪
- 当调用了start方法后,线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时线程处于就绪状态.在线程运行后,冲等待或者睡眠回来后,也会处于就绪状态
-
运行
- 线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始执行run方法
-
阻塞
- 线程正在运行的时候,被暂停,通常为了等待某个时间发生(比如说某项资源就绪)之后再继续运行.sleep,suspend,wait等方法都可以导致线程阻塞。
-
死亡
- 如果一个线程的run方法执行结束或调用stop方法后,该线程就会死亡.对于死亡的线程就无法使用start方法另其就绪
sleep()和wait()有什么区别
- sleep():方法是线程类(Thread)的静态方法,让调用的线程进入睡眠状态,让出执行机会给其他线程等到休眠结束后,线程进入就绪状态和其他线程一起竞争cpu时间. 但是sleep()是静态方法,他不能改变对象的锁机制,当一个synchronized块调用了sleep()方法,线程虽然进入了睡眠状态,但是对象的锁没有被释放,其他线程依然无法访问这个对象
- wait():是一个Object类的方法,当一个线程执行到wait方法时,他就进入到了一个和该对象相关的等待池中,同时释放锁资源,使其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程
notify()和 notifyAll()有什么区别?
- 如果线程调用了对象的wait()方法,那么线程处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁
- 当有线程调用了对象的notifyAll()方法(唤醒所有wait线程)或notify()方法(只能随机唤醒一个wait线程),被唤醒的线程便会进入到该对象的锁池中,锁池中的线程将会去竞争该对象的锁…也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。
- 优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
线程中的run和start有什么区别
- 每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。通过调用Thread类的start()方法来启动一个线程。
- start()方法来启动一个线程,真正实现了多线程,这时无需等run方法体中的代码执行完毕,可以直接继续下面的代码; 如果此时线程处于就绪状态,并没有运行.然后通过此Thread类调用方法的run()称为线程体,他包含了要执行的线程内容,run方法执行结束后,此线程终止.然年cpu调度其他线程
- run()方法是在本线程里的,只是线程里的一个函数,而不是多线程的。 如果直接调用run(),其实就相当于是调用了一个普通函数而已,直接待用run()方法必须等待run()方法执行完毕才能执行下面的代码,所以执行路径还是只有一条,根本就没有线程的特征,所以在多线程执行时要使用start()方法而不是run()方法。
创建线程池有哪几种方式?
-
newFixedThreadPool
- 创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大量,这时线程规模将不再变化,当线程发生未预期的错误结束时,线程池会补充一个新的线程
-
newCachedThreadPool
- 创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,需求增加时,则可以自动添加新的线程,线程池的规模没有限制。
-
newSingleThreadExecutor
- 这是一个单线程的Executor,它创建单个工作线程来执行任务,如果这个线程异常结束,会创建一个新的来替代他;他的特点就是能够确保依照任务在队列中顺序执行
-
newScheduledThreadPool
- 创建一个固定长度的线程池,而且可以延迟或者定时来执行任务,类似于Timer
线程池都有哪些状态?
-
RUNNING
- 这是最正常的状态,接受新的任务,处理等待队列中的任务,线程初始化就是running状态。线程池一旦被创建,就处于running状态,线程池中的任务数为0
-
SHUTDOWN
- 不接受新的任务提交,但是会继续处理等等待队列中的任务。调用线程池的shutdown()方法时,线程池由running变为shutdown
-
STOP
- 不接受新的任务提交,不在处理等待队列中的任务,中断正执行的线程。调用线程池的shotdownNow()方法时,线程池由running和shutdown 变为stop
-
tidying
- 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。
状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。
当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING
- 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。
-
TERMINATED
- 状态说明:线程池彻底终止,就变成TERMINATED状态。
状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。
- 状态说明:线程池彻底终止,就变成TERMINATED状态。
线程池中submit()和execute()方法有什么区别
- 接受参数不一样
- submit有返回值,execute没有返回值
- submit方便Exception处理
java在程序中怎么保证多线程的运行安全
-
原子性
- 提供互斥访问,同一时刻只能有一个线程对数据进行操作(atomic,synchronized)
-
可见性
- 一个线程对主内存的修改可以被其他线程看到(synchronized,volatile)
-
有序性
- 一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)
什么是死锁
- 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。是操作系统层面的一个错误,是进程死锁的简称,最早在 1965 年由 Dijkstra 在研究银行家算法时提出的,它是计算机操作系统乃至整个并发程序设计领域最难处理的问题之一。
怎么防止死锁
-
互斥条件
- 进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
-
请求和保持条件
- 进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
-
不可剥夺条件
- 是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
-
环路等待条件
- 是指进程发生死锁后,若干进程之间形成一种头尾相接的循环等待资源关系
ThreadLocal是什么?有哪些使用场景
- 线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程中共享。java提供的ThreadLocal类来支持线程局部变量,是一种是实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险。
说一下 synchronized 底层实现原理?
- synchronized可以保证方法或者代码块在运行时,同时刻只有一个方法可以进入临界区,同时它还可以保证共享变量的内存可见性。java中每个对象都可以作为锁,这是synchronized实现同步的基础。
- 普通同步方法,锁是当前实例对象
静态同步方法,锁是当前类的class对象
同步方法块,锁是括号里的对象
synchronized和volatile的区别
- volatile本质是告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取;synchronize则锁定当前变量,只有当前线程可以访问该变量,其他被阻塞住
- volatile仅能使用在变量级别;synchronized则可以使用在变量 方法 类 级别
- vloatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
- volatile不会造成线程阻塞;synchroized可能会造成线程阻塞。
- volatile标记的变量不会被编译器优化,synchronized则可以被编译器优化
synchronized和Lock有什么区别
- synchronized是java内置的关键字,而Lock是一个java类
- synchronized无法判定锁的状态,Lock可以获取到锁
- synchronized会自动释放锁,Lock需要在finally中手动释放锁资源,否组容易造成死锁
- 用synchronized关键字的两个线程1和线程2,如果线程1 获得了锁,线程2 线程等待。如果线程1阻塞,线程2则会一直等待下去。而Lock锁就一定等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了
- synchronized锁可以重入 ,不可中断,非公平,而Lock锁可重入,可判断,可公平(两者皆可)
- Lock锁合适大量同步的代码同步问题,synchronized锁适合少量的同步问题
synchronized和ReentranLock区别
- synchronized是java内置关键字,ReentrantLock是Java类。
- ReentrantLock可以获取锁的等待时间设置,这样就避免了死锁
- ReentrantLock可以获取各种锁信息
- ReentrantLock可以灵活的实现多路通知
- 另外,二者的锁机制其实也是不一样的:ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark word。
说一下atomic原理
- Atomic包中的类基本的特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引用类型)变量进行操作时,具有排他性,即当多个线程同时对该变量的值进行更新时,仅有一个线程能成功,而未成功的线程可以向自旋锁一样,继续尝试,一直等到执行成功。
Atomic系列的类中的核心方法都会调用unsafe类中的几个本地方法。我们需要先知道一个东西就是Unsafe类,全名为:sun.misc.Unsafe,这个类包含了大量的对C代码的操作,包括很多直接内存分配以及原子操作的调用,而它之所以标记为非安全的,是告诉你这个里面大量的方法调用都会存在安全隐患,需要小心使用,否则会导致严重的后果,例如在通过unsafe分配内存的时候,如果自己指定某些区域可能会导致一些类似C++一样的指针越界到其他进程的问题。
异常
throw和throws区别
- thorws是用来声明一个方法可能抛出的所有异常信息,throws是将异常抛出但不处理,而是将异常往上传,谁调用谁去处理。而throw则是指怕抛出一个具体的异常类
final,finally,finalize
-
final
- 修饰类 ,变量,方法。不能被重写/修饰变量表示为一个常量被重新赋值
-
finally
- 一般作用在try-catch代码块中,处理异常的时候,通常我们一定要执行的代码方法放入finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
-
finalize
- 属于Object类的一个方法,而Object是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System的gc()方法的时候,垃圾回收器调用finalize()回收垃圾
try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
- 会执行,在 return 前执行。
常见的异常类有哪些?
-
NullPointerException
- 空针异常
-
SQLException
- 数据库访问错误或其他错误异常
-
IndexOutOfBoundsException
- 超出索引范围
-
NumberFormatException
- 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
-
FileNotFoundException
- 当试图打开指定路径名表示的文件失败时,抛出此异常。
-
IOException
- 当发生某种I/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类。
-
ClassCastException
- 当试图将对象强制转换为不是实例的子类时,抛出该异常。
-
ArrayStoreException
- 试图将错误类型的对象存储到一个对象数组时抛出的异常。
-
IllegalArgumentException
- 抛出的异常表明向方法传递了一个不合法或不正确的参数。
-
ArithmeticException
- 当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
-
NegativeArraySizeException
- 如果应用程序试图创建大小为负的数组,则抛出该异常。
-
NoSuchMethodException
- 无法找到某一特定方法时,抛出该异常。
-
SecurityException
- 由安全管理器抛出的异常,指示存在安全侵犯。
-
UnsupportedOperationException
- 当不支持请求的操作时,抛出该异常。
-
RuntimeExceptionRuntimeException
- 是那些可能在Java虚拟机正常运行期间抛出的异常的超类。
网络
http 响应码 301 和 302 代表着什么
- 301,302 都是HTTP状态的编码,都代表着某个URL发生了转移。
forward和redirect的区别
-
forward
- 直接转发方式,客户端和浏览器只发送了一次请求,Servlet, html,Jsp或其他资源,由第二个信息资源相应该请求,在请求对象中request中,保存的对象是共享的
-
redirect
- 间接转发请求,实际是两次http请求,服务端在相应第一次请求的时候,让浏览器再向外发送一个请求,从而达到转发的目的
-
例子
- 直接转发就相当于:“A找B借钱,B说没有,B去找C借,借到借不到都会把消息传递给A”;
间接转发就相当于:“A找B借钱,B说没有,让A去找C借”。
简述tcp和udp的区别
- tcp面向连接;udp是无连接,即发送数据是不需要连接的
- Tcp提供可靠的服务,也就是说,通过TCP连接是无差错,不丢失,不重复的,且按顺序到达;UDP尽最大努力交付,及不保证可靠交付
- TCP通过校验,重传控制,序号表示,滑动窗口,确认应答,实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制
- UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
- TCP是点对点的,而UDP支持一对多,一对一,多对一,和多对多
- TCp对系统资源要求多,UDp对系统资源要求少
tcp为什么要三次握手
- 为了实现可靠数据传输,tcp协议通讯双方,都必须维护一个序列号,以标识发送出去的数据包中,哪些是已经被对方收到的。三次握手的过程是通讯双方相互告知序列号的起始值,并确认对方已经收到序列号起始值的毕竟步骤
- 如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。
ios七层
-
应用层
- 网络服务与最终用户的一个接口。
-
表示层
- 数据的表示、安全、压缩。
-
会话层
- 建立、管理、终止会话。
-
传输层
- 定义传输数据的协议端口号,以及流控和差错校验。
-
网络层
- 进行逻辑地址寻址,实现不同网络之间的路径选择。
-
数据链路层
- 建立逻辑连接、进行硬件地址寻址、差错校验等功能。
-
物理层
- 建立、维护、断开物理连接。
get 和post 有哪些区别
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST么有。
- 参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- ET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
跨域问题
-
图片ping或script标签跨域
-
JSONP跨域
- jsonp 即 json+padding,动态创建script标签,利用script标签的src属性可以获取任何域下的js脚本,通过这个特性(也可以说漏洞),服务器端不在返货json格式,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。
-
CORS
-
window.name+iframe
-
window.postMessage()
-
修改document.domain跨子域
-
WebSocket
-
代理
XMind - Trial Version