面试题汇总
简述线程、进程、程序的基本概念?
进程: 我们把运行中的程序叫做进程,每个进程都会占用内存与CPU资源,进程与进程之间互相独立.
线程: 线程就是进程中的一个执行单元,负责当前进程中程序的执行。一个进程可以包含多个线程。多线程可以提高程序的并行运行效率。
程序:是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。
创建线程的几种方法
Thread
Runnable
Callable
线程有什么优缺点?
优点:
1. 在多核CPU中,通过并行计算提高程序性能. 比如一个方法的执行比较耗时,现在把这个方法逻辑拆分,分为若干个线程并发执行,提高程序效率。
2. 可以解决网络等待、io响应导致的耗时问题。
3. 提高CPU的使用率.提高网络资源的利用率
缺点:
1. 线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
2. 线程之间对共享资源的访问会造成资源安全问题;
3. 多线程存在上下文切换问题CPU 通过时间片分配算法来循环执行任务,所以本身就会占用cpu资源。
start 和 run 方法有什么区别?
调用start方法方可启动线程,而run方法只是thread类中的一个普通方法调用,还是在主线程里执行。
可以直接调用Thread类的run()方法吗
可以直接调用,但是只是执行了一个普通的run方法而已,并没有真正的启动线程
Thread类的 sleep 方法和对象的 wait 方法都可以让线程暂停执行,它们有什么区别?
1、sleep()方法是属于Thread类中的,而wait()方法,则是属于Object类中的。
2、sleep()方法导致了程序暂停执行指定的时间,让出cpu给其他线程,当指定的时间到了又会自动恢复运行状态。所以在调用sleep()方法的过程中,线程不会释放对象锁。
3、调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后该线程才准备获取对象锁进入运行状态。
notify 和 notifyAll 有什么区别?
notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。
notifyAll 会唤醒所有等待(对象的)线程,线程优先级处理取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll 方法。
sleep、join、yield 方法有什么区别?
sleep让程序暂停执行指定的时间,让出cpu给其他线程执行
t.join()方法会使主线程进入等待池并等待t线程执行完毕后才会被唤醒。并不影响同一时刻处在运行状态的其他线程。t.join()中的t优先执行,当t执行完后才会执行其他线程。能够使得线程之间的并行执行变成串行执行。
线程调用了join方法,那么就要一直运行到该线程运行结束,才会运行其他线程. 这样可以控制线程执行顺序。
thread.yield() 让CPU的时间片,尽量切换其他线程去执行
线程生命周期(几种状态)
NEW:初始状态,线程被创建,但是还没有调用start方法
RUNNABLED:运行状态,调用start方式让线程处于“运行中”
BLOCKED:阻塞状态,表示线程进入等待状态,也就是线程 因为某种原因放弃了CPU使用权,阻塞也分为几种情况
➢ 同步阻塞:运行的线程在获取锁时,若该锁被其他线程占用了,那么当前线程会阻塞
➢ 其他阻塞:运行的线程执行Thread.sleep或者t.join方法时,称为其他阻塞
WAITING:调用wait等方法等待,等待唤醒(notify或notifyAll)
TIME_WAITING:超时等待状态,等待另一个线程在指定的时间访问唤醒,超时以后线程状态就是TIME_WAITING
TERMINATED:终止状态,表示当前线程执行完毕
为什么代码会重排序?
重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。
Java关键字volatile作用
1、 保证变量的可见性
2、 防止指令重排序
了解volatile底层如何保证可见性的吗
我们从JMM层面来回答:
对volatile变量执行写操作的时候,在写操作后面会加一个指令加store指令,会强制刷新到主内存中
对volatile变量执行读操作的时候,在读操作后面会加一个指令加load指令,会强制到主内存中读取,而不是到工作内存读取
Java关键字synchronized作用以及原理?
作用:synchronized 当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码,使得程序保持同步性
原理:JVM 是通过进入、退出对象监视器( Monitor )来实现对方法、同步块的同步的
可以通过javap -c xx.class反编译指令查看指令
除了synchronized之外你还使用过哪些锁?
java在1.5提供了lock锁
请你描述一下怎么使用lock锁的?
Lock lock = new ReentrantLock();
try{
lock.lock();
//可能会出现线程安全的操作
}finally{
//尽量在finally中释放锁
lock.unlock();
}
Lock和synchronized区别
1. synchronized 是内部锁,自动化的上锁与释放锁,而lock是手动的,需要人为的上锁和释放锁,lock比较灵活,但是代码量多
2、lock是一个接口,而synchronized是Java中的关键字
3、性能上来说,在资源竞争不激烈的情形下,Lock性能稍微比synchronized差点。但是当并发非常激烈的时候,synchronized的性能就会下降几十倍。而ReentrantLock确还能维持常态。
线程池的优点
1. 避免创建线程和销毁线程的性能开销
2. 提高响应速度
3. 线程池的线程可以重复使用
介绍一下java中的线程池执行流程
什么是死锁
死锁就是两个或两个以上的线程被无限的阻塞,线程之间相互等待所需资源。这种情况可能发生在当两个线程尝试获取其它资源的锁,而每个线程又陷入无限等待其它资源锁的释放,除非一个用户进程被终止,一个线程占用了另外一个线程必需的锁,互相等待时被阻塞就有可能出现死锁
说说你最熟悉的同步工具类
Semaphore
就是一个信号量,它的作用是限制某段代码块的并发数
具体使用:见笔记
CountDownLatch
可以是多个线程按照特定的顺序来执行流程,保证在多线程环境下程序的顺序性
具体使用:见笔记