没有合适的资源?快使用搜索试试~ 我知道了~
首页史上最全的Java核心技术总结.pdf
史上最全的Java核心技术总结.pdf
5星 · 超过95%的资源 需积分: 50 90 下载量 16 浏览量
更新于2023-03-03
评论 9
收藏 1.48MB PDF 举报
史上最全的Java核心技术总结,涵盖了jvm、java核心技术、java并发编程、计算机网络等重点面试知识。通过总结面过阿里、网易、美团、京东、一二面无压力。
资源详情
资源评论
资源推荐
1
、线程状态转移
(
1
)线程生命周期中的
5
种状态
新建(
N
ew)、就绪(Runnable)、运行(Running)、阻塞(Bolocked)和死亡(Dead)
新建(New)
:程序使用new关键字创建一个线程之后,该线程就处于新建状态,仅仅由Java虚拟机为其分配内存,并初始化其成员变量的值。不会执行线程的线程执行体。
就绪(Runnable)
:线程对象调用start()方法后,该线程处于就绪状态,Java虚拟机会为其创建方法调用栈和程序计数器(线程私有),处于就绪状态的线程并没有开始运行,只是表示该线程
可以运行,线程何时运行取决于JVM中线程调度器的调度。
运行(Running)
:处于就绪状态的线程获得
CPU
,开始执行run()方法的线程执行体,则该线程处于运行状态。
线程调用sleep()方法主动放弃所占用的处理器资源;
•
线程调用一个阻塞式IO方法,在该方法返回之前,该线程被阻塞;
•
线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有;
•
线程在等待某个通知(notify);
•
程序调用了线程的suspend()方法将该线程挂起,但这个方法易造成死锁,应该避免使用。
•
阻塞(Boloked)
:当调用sleep()、一个阻塞式IO方法、同步锁、等待通知、suspend()方法挂起都会使线程进入阻塞状态。(Blocked、Waiting、Timed_Waiting)
run()或call()方法执行完成,线程正常结束;可以设置一个flag标志位来控制循环是否执行,让线程离开run()方法;
•
线程抛出一个未捕获的Exception或Error;使用interrupt()方法打破阻塞状态,抛出InterruptedException异常,在run()方法中捕获该异常来让线程安全退出;
•
直接调用该线程的stop()方法来结束该线程(该方法易造成死锁,不推荐使用)
•
死亡(Dead)
:以如下3种方式结束线程(
终止线程的方法
)
调用sleep()方法的线程经过了指定时间;
•
线程调用的阻塞式IO方法已经返回;
•
线程成功地获得试图取得的同步监视器(锁);
•
线程正在等待某个通知时,其他线程发出了一个通知;
•
处于挂起状态的线程被调用了resume()恢复方法。
•
补充:线程从
阻塞状态解除——进入就绪状态
的过程:
1)start()是启动线程,让线程从新建状态变为就绪状态;线程得到CPU时间片后,执行run()中的线程执行体;
•
2)start()只能调用一次;run()可以重复调用。
•
3)启动线程只能用start(),系统会把run()方法当做线程执行体处理;如果直接调用run(),系统会把线程对象当作普通对象,此时run()也是一个普通方法,而不是线程执行体。
•
4)源码中:start()源码中实际上通过本地方法start0()启动线程,会新运行一个线程,新线程会调用run()方法;而run()源码中target是Runnable对象,run()直接调用Thread线程的
Runnable成员的run()方法,并不会新建一个线程。
•
(
2
)
start()
方法和
run()
方法的区别
(
3
)
wait()
和
sleep()
的区别
1)原理不同:wait()属于Object类;sleep()属于Thread类的静态方法;
2)锁的处理:wait()会导致线程释放对象的锁;sleep()导致当前线程让出CPU执行时间但不会释放对象的锁;
3)唤醒方式:wait()通过等待其他线程notify()或notifyAll()唤醒或者指定一个时间;sleep(long millis)是Thread的静态方法,经过指定时间后从阻塞状态进入就绪状态;
4)使用区域:wait()必须放在同步控制方法或者同步语句块中使用;而sleep()方法可以放在任何地方使用。
(
4
)创建线程的三种方式
1)继承Thread类创建线程类;
2)实现Runnable接口创建线程类;
3)使用Callable和Future创建线程。
1.定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表线程需要完成的任务。run()即为线程执行体;
•
2.创建Thread子类的实例,即创建线程对象;
•
3.调用线程对象的start()方法来启动该线程。
•
1
)继承
Thread
类创建线程类;
1.定义Runnable接口的实现类,并实现该接口的run()方法,该run()是线程执行体;
•
2.创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象;
•
3.调用线程对象的start()方法来启动该线程。
•
2
)实现
Runnable
接口创建线程类;
1.创建Callable接口的实现类,并实现call()方法,该call()方法即为线程执行体,且该call()方法有返回值,再创建Callable实现类的实例;
•
2.使用FutureTask类包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值;
•
3.使用FutureTask对象作为Thread对象的target创建并通过线程对象的start()方法启动线程;
•
4.调用FutureTask对象的get()方法获得子线程执行结束后的返回值。
•
3
)使用
Callable
和
Future
创建线程。
1)
返回值
:继承Thread类,run()方法没有返回值;实现Runnable接口和Callable接口方式基本相同,但Callable接口定义的call()方法具有返回值,可以声明抛出异常;
•
2)
继承
:继承Thread类,不能再继承其他类;线程类实现Runnable和Callable接口可以继承其他类;
•
3)
访问当前线程
:继承Thread类,需要访问当前线程,无须使用Thread.currentThread()方法,直接使用this即可获得当前线程;线程类实现Runnable和Callable接口,若访问当前线
程,必须使用Thread.currentThread()方法。多个线程共享同一个target对象,适合多个相同线程来处理同一份资源的情况,从而将CPU、代码和数据分开,形成清晰的模型,较好地体现
面向对象思想;
•
4
)三种方式的区别
综合:推荐使用线程类实现Runnable和Callable接口方式创建多线程。
prepared
2017年5月12日, 星期五
07:31
分区 总结整理 的第
1
页
综合:推荐使用线程类实现Runnable和Callable接口方式创建多线程。
(
5
)为什么
notify()
、
wait()
等函数是定义在
Object
中而不是在
Thread
中?
因为notify(),wait()依赖于”同步锁“,而”同步锁“是对象所持有,并且每个对象有且只有一个。
1)yield()是Thread类的一个静态方法,作用是让步而不会阻塞线程,让当前线程从“运行状态”进入“就绪状态”,让具有相同优先级或更高优先级的等待线程获取CPU执行权(当前线
程有可能再次进入到“运行状态”)
•
2)yield()和sleep(long millis)的区别:yield()从Running进入Runnable状态,极有可能被调度选中继续运行;sleep(long millis)使线程进入Blocked状态且会等待超时时间后再进入
Runnable状态,之后再等线程调度器的调度。
•
3)yield()和wait()的区别:wait()让线程由Running进入Blocked or Waiting状态,会释放同步锁。
•
(
6
)
yield()
方法
1)sleep(long millis)方法是Thread类的一个静态方法,作用是让当前线程暂停一段时间,并进入阻塞状态。
•
2)两种重载形式:static void sleep(long millis)和static void sleep(long millis, int nanos),其中millis单位是毫秒,nanos单位是毫微秒。
•
3)sleep(long millis)方法常用来暂停程序的执行,进入阻塞状态后,在其睡眠时间段内,该线程不会获得执行机会(即使系统没有其他可执行的线程,处于sleep()中的线程也不会执行)。
•
4)sleep(long millis)和wait()方法的区别:wait()会释放同步锁。
•
5)sleep()方法不会释放“锁标志”,容易引起死锁问题。
•
(
7
)
sleep()
方法
1)
优先级
:sleep()方法给其他线程运行机会时,不考虑线程的优先级,低优先级的线程有可能回运行;yield()方法只会给相同优先级或更高优先级的线程运行的机会;
•
2)
状态
:sleep()方法使得线程转入阻塞撞他,在指定时间内不会执行;而yield()方法只是使当前线程重新回到就绪状态,所以当前线程有可能在进入到就绪状态后马上又被执行;
•
3)
异常
:sleep()方法声音抛出InterruptedException异常;而yield()方法没有声明任何异常;
•
4)
可移植性
:sleep()比yield()方法(跟操作系统有关)具有更好的可移植性。
•
(
8
)
sleep()
与
yield()
的比较
2
、
ReentrantLock
的理解
(
1
)
ReentrantLock
的介绍
1)Lock提供一种无条件的、可轮询的、定时的以及可中断的锁获取操作,所有加锁和解锁都是显式的。
2)ReentrantLock实现Lock接口,并提供与synchronized相同的互斥性和内存可见性。
3)ReentrantLock提供和synchronized一样的可重入的加锁语义。
4)ReentrantLock是显式锁,需要显式进行lock以及unlock操作。形式比内置锁复杂,必须在finally块中释放锁,否则如果在被保护的代码中抛出异常,这个锁就永远都无法释放。加锁时,需
要考虑在try块中抛出异常的情况,如果可能使对象处于某种不一致的状态,则需要更多的try-catch或try-finally代码块。
Lock lock = new ReentrantLock();
...
lock.lock();
//
更新对象状态
//
捕获异常,并在必要时恢复不变性条件
try{
lock.unlock();
}finally{
}
(
2
)使用
ReentrantLock
的灵活性(也是与synchronized的区别)
1)等待可中断
使用lock.lockInterruptibly()可以使得线程在等待锁支持响应中断;
使用lock.tryLock()可以使线程在等待一段时间过后如果还未获得锁就停止等待而非一直等待,更好的避免饥饿和死锁问题;
2)公平锁
默认情况下是非公平锁,但是可以成为公平锁,公平锁就是锁的等待队列的FIFO,不建议使用,会浪费许多时钟周期,达不到最大利用率。
3)锁可绑定多个条件
与ReentrantLock搭配的通信方式是Condition,且可以为多个线程建立不同的Codition
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
condition.await(); //
等价于synchronized中的wait()方法
condition.signal(); //
等价于notify()
condition.signalAll(); //
等价于notifyAll()
(
3
)为什么要创建一种与内置锁相似的新加锁机制?
内置锁能很好的工作,但是在功能上存在一些局限性,如
synchronized无法中断一个正在等待获取锁的线程
,或者
无法在请求获取一个锁的时候无限地等待下去
,内置锁必须在获取该锁的
代码块中释放,简化了编码工作,且与异常处理操作实现很好的交互,
但无法实现非阻塞结构的加锁机制
。所以需要提供一种更灵活的加锁机制来提供更好的活跃性或性能。
(
4
)
synchronized
和
ReentrantLock
的抉择
1)当需要可定时的、可轮询的、可中断锁、公平锁以及非块结构的锁(锁分段技术)时,才使用ReentrantLock,否则优先使用synchronized,毕竟现在JVM内置的是synchronized。
2)ReentrantLock的危险性,如果在try-finally中,finally未进行unlock,就会导致锁没有释放,无法追踪最初发生错误的位置。
(
5
)读
-
写锁
ReadWriteLock
互斥锁,虽然避免了“写/写”冲突和“写/读”冲突,但也避免了“读/读”冲突,而大部分读操作比较多,且读操作不会改变数据,所以ReentrantLock提供的非互斥的读写锁,可以放宽加
锁需求,允许多个读操作访问一个资源,实现更高的并发性,提升程序的性能。
3
、
synchronized
的理解
1)synchronized机制提供了对与每个对象相关的隐式的监视器锁,并强制所有锁的获取和释放都必须在同一个块结构中。当获取了多个锁时,他们必须
以相反的顺序释放。
即
synchronized对于锁的释放是隐式的。
•
2)synchronized同步块对同一条线程是
可重入
的,不会出现自己把自己锁死的问题。
•
3)synchronized可以修饰类、方法(包括静态方法)、代码块。修饰类和静态方法时,锁的对象是Class对象;修饰普通方法时,锁的是调用该方法的对象;修饰代码块时,锁的是方法块
括号里的对象。
•
4)synchronized性能中会避免“读/读”操作,但读操作频繁,通过ReentrantLock提供的ReadWriteLock读写锁来解决该问题;阻塞线程时,需要OS不断的从用户态转到核心态,消耗处
理器时间,通过自适应自旋来解决该问题。
•
5)synchronized的锁是存放在Java对象头里。
•
6)当一个线程进入一个对象的一个synchronized方法后,其他线程可以进入此对象的其他非synchronized方法或者调用静态的synchronized方法;如果要调用其他synchronized方法,
则必须在该方法内部调用wait()方法。
•
(
1
)
synchronized
的介绍
(
2
)
synchronized
方法和
synchronized
块的区别
1)
synchronized块
则是一种
细粒度
的并发控制,只会将块中的代码同步,位于方法内、synchronized块之外的代码是可以被多个线程同时访问到的,锁的是方法块后面括号里的对象;
synchronized方法
是一种
粗粒度
的并发控制,某一时刻,只能有一个线程执行该synchronized方法,锁的是调用该方法的对象。
2)
同步代码块
:monitorenter指令插入到同步代码块的开始位置,monitorexit指令插入到同步代码块的结束位置,JVM需要保证每一个monitorexit和monitorenter相对应,任何对象都有一
分区 总结整理 的第
2
页
2)
同步代码块
:monitorenter指令插入到同步代码块的开始位置,monitorexit指令插入到同步代码块的结束位置,JVM需要保证每一个monitorexit和monitorenter相对应,任何对象都有一
个monitor与之相对应,任何对象都有一个monitor与之相关联,当且一个monitor被持有之后,他处于锁定状态,线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor所有
权,即尝试获取对象的锁;
同步方法
:synchronized方法则会被翻译成普通的方法调用和返回指令如:invokevirtual、areturn指令,在VM字节码层面并没有任何特别的指令来实现被
synchronized修饰的方法,而是在
Class文件的方法表
中将该方法的
access_flags字段中的synchronized标志位置1
,表示该方法是
同步方法并使用调用该方法的对象
或该方法所属的Class在
JVM的内部对象表示Klass做为锁对象。在常量池中添加了ACC_ SYNCHRONIZED标识符,JVM就是根据该标识符来实现方法的同步。
synchronized关键字经编译后,在
同步块
前后分别形成
monitorenter和monitorexit
两个字节码指令;
1.
在执行monitorenter指令时,首先要尝试获取对象的锁,若这个对象没被锁定,或当前线程已经拥有了那个对象的锁,就把
锁的计数器加1
;
2.
在执行monitorexit指令时会将锁计数器减1,当计数器为0时,锁就会被释放;
3.
若获取对象锁失败,当前线程进入阻塞等待,直到对象锁被另外一个线程释放为止。
4.
(
3
)
synchronized
字节码层面实现的锁(锁计数器)。
(
4
)
synchronized
和
ReentrantLock
的异同
都是可重入的,都属于同步互斥的手段;
•
同:
用法
:synchronized是原生语法层面的互斥锁,加载同步方法或者同步代码块;ReentrantLock是API层面的互斥锁,显式地指定起始位置和终止位置;
•
锁机制
:synchronized是内置锁,获取多个锁后,以相反的顺序隐式释放锁;ReentrantLock必须显式加锁释放锁,且可以自由的顺序释放锁。
•
功能
:ReentrantLock增加高级功能:等待可中断、可实现公平锁、锁可以绑定多个条件。
•
异:
(
5
)重入锁
重入锁实现重入性:
每个
锁关联一个线程持有者和计数器
,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下
锁的持有线程,并且将计数器置为1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计
数器会递减,如果计数器为0,则释放该锁。
(
6
)对象头
1)对象头中包括两部分数据:标记字段和类型指针;
2)类型指针Klass Point是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;
3)标记字段Mark Word是一个非固定的数据结构,用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等。
(
7
)锁优化
1)jdk1.6对锁进行优化:自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁。
4
、
volatile
的理解
(
1
)
volatile
的介绍
1)volatile是比synchronized关键字更轻量级的同步机制:访问volatile变量时不会执行加锁操作,因此不会使执行线程阻塞。
2)volatile保证可见性和禁止指令重排序,底层是通过“内存屏障”来实现,但不保证原子性。
3)写入volatile变量相当于退出同步代码块,读取volatile变量相当于进入同步代码块。
(
2
)可见性以及禁止指令重排序实现原理
1)
可见性
:可见性指当一条线程修改该变量值,新值对于其他线程来说是立即得知的。volatile底层通过lock前缀,作用使得本CPU的Cache写入内存,该写入动作也会引起别的CPU或者别的内
核无效化其Cache,相当于对Cache中的变量进行了JMM的“store和write”操作,本线程使其他线程的该变量的缓存行无效,当其他线程需要读该变量时发现该变量缓存行无效,就从主存中重
新加载数据,所以保证了数据的可见性。
2)
禁止指令重排序优化
:volatile修饰的变量会在汇编代码中多执行一个lock操作,相当于一个内存屏障(Memory Barrier,指重排序时不能把后面的指令重排序到内存屏障之前的位置),只
有一个CPU访问内存时并不需要内存屏障;但若有多个CPU访问同一块内存,且其中有一个在观测另一个,就需要内存屏障来保证一致性。lock指令把修改同步到内存时,意味着所有之前的操作
都已经执行完毕,形成“指令重排序无法越过内存屏障”的效果。
对变量的写入操作不依赖变量的当前值,或能确保只有单个线程更新变量的值;
•
该变量不会与其他状态变量一起纳入不变性条件中;(该变量没有包含在其他变量的不变式中)
•
在访问变量时不需要加锁。
•
(
3
)
volatile
的使用场景
1.
当前线程每次使用变量前都必须先从主内存刷新最新的值,用于保证能看到其他线程对变量的修改。(read、load、use连续执行。)
•
2.
当前每次修改变量后都必须立刻同步到主内存中,用于保证其他线程可以看到自己对线程的修改。(assign、store、write连续执行。)
•
3.
volatile修饰的变量不会被指令重排序优化,保证代码的执行顺序与程序的顺序相同。
•
(
4
)
JMM
对
volatile
变量定义的特殊规则:
(
5
)
as-if-serial
语义允许对存在控制依赖的操作做重排序的原因
在单线程程序中,对存在控制依赖的操作重排序,不会改变执行结果;但在多线程程序中,对存在控制依赖的操作重排序,可能会改变程序的执行结果。
(
6
)
happen-before
先行发生原则
1)顺序执行代码规则:同一个线程中的,前面的操作 happen-before 后续的操作;
2)synchronized规则:监视器上的解锁操作 happen-before 其后续的加锁操作;
3)volatile规则:对volatile变量的写操作 happen-before 后续的读操作;
4)线程启动规则:线程的start() 方法 happen-before 该线程所有的后续操作;
5)线程所有的操作 happen-before 其他线程在该线程上调用 join 返回成功后的操作;
6)传递性:如果a happen-before b,b happen-before c,则a happen-before c。
1.普通成员变量
:抽象类中可以有普通成员变量,接口中没有普通成员变量(static final变量);
•
2.方法:抽象类中可以
包含
非抽象的普通方法
,
接口
中的所有
方法必须都是抽象
的,不能有非抽象的普通方法;
•
3.静态成员变量
:
抽象类和接口
中都可以
包含静态成员变量
,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是
public static final
类型,并且默认即为public
static final类型。
•
4.静态方法:抽象类
中可以
包含静态方法
,但不能是抽象静态方法;接口中不能包含静态方法(静态的方法不能被覆写)
•
5.构造方法(静态的)
:抽象类可以有构造方法,接口中不能有构造方法;
•
6.方法访问权限
:抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然eclipse下不报错,但应该也不行),但
接口
中的抽象方法只能是
public类型
的,并且默认即
为public abstract类型。
•
7.子类实现和继承
: 一个类可以实现多个接口,但只能继承一个抽象类。
•
5
、抽象类和接口的区别
特点
抽象类
接口
构造方法
有
无
普通成员变量
有
无
分区 总结整理 的第
3
页
普通成员变量
有
无
普通方法
可以有非抽象的
必须是抽象的
抽象方法的访问类型
public、protected和默认
只能是public的,默认public abstract
静态方法
可以有
无
静态成员变量
有
有 public static final的
其他类
只能继承一个抽象类
可以实现多个接口
应用场景
模块之间通信契约
代码重用
6
、高速缓存的出现以及缓存一致性问题。
(
1
)高速缓存出现的原因?
答:由于计算机的存储设备(内存读写慢)与处理器的运算速度(快)有几个数量级的差距,加入一层读写速度尽可能接近处理器运算速度的高速缓存
作为内存与处理器之间的缓冲
。
高速缓存的
原理
:将运算需要使用的数据复制到缓存中,让运算能快速进行,当运算结束后,再从缓存中同步回内存之中,这样处理器就无须等待缓慢的内存读写了。
(
2
)缓存一致性问题?
答:在多处理器系统中,每个处理器都有自己的高速缓存,它们之间又共享同一主内存,当多个处理器的运算任务都涉及同一块主内存时,将可能导致各自的缓存数据不一致,则同步到主内存时
数据不统一。
解决方案
:各个处理器访问缓存时遵守一些缓存一致性协议。
7
、
JMM
内存模型
(
1
)工作内存与主内存
主内存:JMM规定所有变量都存储在主内存中(相当于Java堆中对象实例部分),相当于所有工作内存之间变量的中转站。
工作内存:每条线程都有自己的工作内存,保存了呗线程使用到的变量的主内存副本拷贝。线程对变量的读写都必须在工作内存中进行,对应Java虚拟机栈中的部分区域。
(
2
)工作内存与主内存之间的交互操作:
lock、unlock、read、load、use、assign、store、write
操作
作用区域
作用
lock(锁定)
主内存变量
把一个变量标识为一条线程独占的状态。
unlock(解锁)
主内存变量
把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
read(读取)
主内存变量
把一个变量的值从主内存传输到线程的工作内存中,便于load的使用。
load(载入)
工作内存变量
把read操作从主内存得到的变量值放入工作内存的变量副本中。
use(使用)
工作内存变量
把工作内存中的一个变量值传递给执行引擎,每当VM遇到一个需要使用变量值的字节码指令时执行。
assign(赋值)
工作内存变量
把一个从执行引擎接收到的值赋给工作内存的变量,每当VM遇到一个给变量赋值的字节码指令时执行。
store(存储)
工作内存变量
把工作内存中的一个变量值传送到主内存中,便于write的使用。
write(写入)
主内存变量
把store操作从工作内存得到的变量值放入主内存的变量中。
8
、原子性、可见性和有序性
(
1
)原子性
原子性就是指:一个操作或多个操作,要么全部执行且执行的过程不被任何因素打断,要么就都不执行。基本数据类型的访问读写是具有原子性的(除了long和double64位)
(
2
)可见性
可见性是指:当一个线程修改共享变量的值,其他线程能够立即得知这个修改。(
JMM
通过在变量修改后将新值同步回主内存,在其他线程读取该变量时,从主内存刷新变量值的方式保证可见
性。)
(
3
)有序性
volatile禁止指令重排序(底层是通过内存屏障实现,内存屏障后面的操作不会先于前面的操作发生,所以保证前面的操作都完成后,再完成后面的操作);synchronized是一个变量在同一个时
刻只允许一条线程对其lock操作,即持有同一个锁的两个同步块只能串行地进入。
9
、先行发生原则(
happens-before
)
(
1
)先行发生原则的介绍
1)先行发生原则是判断数据是否存在竞争、线程是否安全的主要依据。
2)JMM定义的两个操作之间的偏序关系。如操作A先行发生于操作B,则在发生操作B之前,操作A的影响(修改内存中共享变量的值、发生消息、调用方法)会被操作B观察到。
(
2
)先行发生原则的
8
个
规则
介绍
分区 总结整理 的第
4
页
程序次序规则
在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。(控制流顺序,如分支、循环等结构)
管程锁定规则
一个unlock先行发生于后面对
同一个锁
的lock操作。
volatile变量规则
对一个volatile变量的写操作先行发生于后面对这个变量的读操作。
线程启动规则
Thread对象的start()方法先行发生于此线程的每一个动作。
线程终止规则
线程中的所有操作都先行发生于对此线程的终止检测。通过Thread.join()方法结束、Thread.isAlive()的返回值检测到线程已经终止。
线程中断规则
对线程interrupt()方法的调用先行发生于被中断的代码检测到中断事件的发生,可通过Thread.interrupted()方法检测到是否有中断发生。
对象终结规则
一个对象的初始化完成(构造函数执行结束)先行发生于finalize()方法的开始。
传递性
操作A先行发生于操作B,操作B先行发生于操作C,则操作A先行发生于操作C。
1.查询插入等用途(顺序性)
:在Map中插入、删除和定位元素,HashMap适合;若要按顺序遍历键,则TreeMap适合。
•
2.底层优化
:HashMap可以调优初始容量和负载因子;TreeMap没有调优选项,因为树总处于平衡状态。
•
3.实现接口
:都实现了Cloneable接口。HashMap继承AbstractMap;TreeMap实现SortMap接口,能够把它保存的记录根据键排序(默认按键的升序)。
•
4.底层实现
:HashMap底层是数组+链表法;TreeMap底层是数组+红黑树。(从Java 8开始,HashMap,ConcurrentHashMap和LinkedHashMap在处理频繁冲突时将使用平衡树来代
替链表,当同一hash桶中的元素数量超过特定的值(默认为8)便会由链表切换到平衡树,这会将get()方法的性能从O(n)提高到
O(logn)
。)
•
10、HashMap和TreeMap
11、HashMap和Hashtable
同:
两者都是用key-value方式获取数据。
1.null值
:HashMap允许null值作为key和value;Hashtable不允许null的键值;
•
2.顺序性
:HashMap不保证映射的顺序不变,但是作为HashMap的子类LinkedHashMap默认按照插入顺序来进行映射的顺序;Hashtable无法保证;
•
3.线程安全
:HashMap是非同步的(非线程安全),效率高;Hashtable是同步的(线程安全的),效率低。(HashMap同步通过Collections.synchronizedMap()实现)
•
4.快速失败机制
:迭代HashMap采用fail-fast快速失败机制(快速失败机制:是一个线程或软件对于其故障做出的响应,用来即时报告可能会导致失败的任何故障情况,如果一个Iterator在
集合对象上创建了,其他线程想结构化的修改该集合对象,抛出并发修改异常ConcurrentModificationException);而HashTable的enumerator迭代器不是fail-fast的(Hashtable的上
下文同步:一个时间点只能有一个线程可以修改哈希表,任何线程在执行Hashtable的更新操作前需要获取对象锁,其他线程等待锁的释放;
•
5.父类
:HashMap继承AbstractMap,Hashtable继承Dictionary;
•
6.数组默认大小
:HashMap底层数组的默认大小是16,扩容是2*old;Hashtable底层数组默认是11,扩容方式是2*old+1;
•
7.效率
:HashMap是非线程安全的,单线程下效率高;Hashtable是线程安全的,方法都加了synchronized关键字进行同步,效率较低;
•
8.计算hash方式不同
:HashMap是二次hash,对key的hashCode进行二次hash,获得更好的散列值;而Hashtable是直接使用key的hashCode对table数组进行取模。
•
异:
如何让HashMap同步
通过Collections集合工具类中的synchronizedMap()方法实现同步:Map map = Collections.synchronizedMap(hashMap);
Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedTMBap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操
作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步,类似的其它
Collections.synchronizedXX方法也是类似原理
Collection是集合类的顶层接口,主要子接口由List、Set和Queue组成。
•
Collections是针对集合类的工具类,提供操作集合的一系列静态方法,如线程安全化、搜索、排序等操作。
•
Collections的用法:当一个集合被作为参数传递给一个函数时,如何才可以确保函数不能修改它:在作为参数传递之前,我们可以使用Collections.unmodifiableCollection(Collection c)
方法创建一个只读集合,这将确保改变集合的任何操作都会抛出UnsupportedOperationException。
•
12、Collection和Collections的区别
底层实现
:ArrayList实现是基于
动态数组
的数据结构,LinkedList是基于
链表
的数据结构(双向链表);
1.
查询
:对于随机访问get和set,ArrayList支持,LinkedList不支持,因为LinkedList要移动指针;
2.
增删
:对于新增和删除操作add和remove,在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
3.
应用场景
:ArrayList适合一列数据的后面添加数据而不是在前面或中间,且需要随机访问元素;LinkedList适合在一列数据的前面或中间添加或删除数据,且按照顺序访问其中的元素。
4.
消耗内存
:LinkedList比ArrayList消耗更多的内存,因为LinkedList中的每个节点都存储前后节点的引用。(双向链表)
5.
13、ArrayList和LinkedList的区别?
14、ArrayList和Vector的区别?
1.线程安全性:ArrayList是非线程安全的,Vector是线程安全的,如果需要在迭代的时候对列表进行改变,使用CopyOnWriteArrayList。
2.效率:ArrayList是非同步的,效率高;Vector是同步的,效率低;
15、Hashmap和Hashset区别
public
HashSet() {
1.
map =
new
HashMap<>();
2.
}
3.
private static final
Object PRESENT =
new
Object();
4.
public boolean
add(E e) {
5.
return
map.put(e, PRESENT)==
null
;
6.
}
7.
HashSet底层是通过HashMap实现的
1.
实现接口
:HashSet实现了set集合的接口,不允许有重复的值(准确说应该是元素作为key,value是定义为final的对象),将对象存储在HashSet之前,需要确保对象已经重写了equals
和hashCode方法,这样才能比较两个对象的值是否相等,确保set中没有存储相等的对象。HashMap实现了map集合接口,对键值对进行映射。Map中不允许重复的键。
•
2.
存储元素
:HashMap存储的是键值对,不允许有重复的键;Hashset存储的是对象,不允许有重复的对象。
•
3.
添加元素方法
:HashMap使用put方法将元素放入map中,HashSet使用add方法将元素放入set中。
•
4.
hashCode值的计算
:HashMap中使用键对象计算hashcode的值,HashSet中使用成员对象来计算hashcode值。
•
5.
效率
:HashMap比较快,因为使用唯一的键来获取对象,HashSet比HashMap慢。
•
6.
底层实现
:HashSet是所有value值都相同的HashMap。HashSet内部使用HashMap实现,只不过HashSet里面的HashMap所有的value都是同一个object而已。private transient
HashMap<E,Object> map;只是包含了hashmap的key。
•
add的时候,调用map的put方法,value始终是PRESENT,所以
HashSet是所有value值都相同的HashMap
。
分区 总结整理 的第
5
页
剩余21页未读,继续阅读
Andya_net
- 粉丝: 173
- 资源: 3
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- ExcelVBA中的Range和Cells用法说明.pdf
- 基于单片机的电梯控制模型设计.doc
- 主成分分析和因子分析.pptx
- 共享笔记服务系统论文.doc
- 基于数据治理体系的数据中台实践分享.pptx
- 变压器的铭牌和额定值.pptx
- 计算机网络课程设计报告--用winsock设计Ping应用程序.doc
- 高电压技术课件:第03章 液体和固体介质的电气特性.pdf
- Oracle商务智能精华介绍.pptx
- 基于单片机的输液滴速控制系统设计文档.doc
- dw考试题 5套.pdf
- 学生档案管理系统详细设计说明书.doc
- 操作系统PPT课件.pptx
- 智慧路边停车管理系统方案.pptx
- 【企业内控系列】企业内部控制之人力资源管理控制(17页).doc
- 温度传感器分类与特点.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论2