线程相关面试题

同一个线程对象可以被启动两次?

join一个已经结束的线程,会怎样
直接执行join下面的逻辑

java怎么开启线程
继承thread ; 实现runnable callable completableFuture ; 线程池

怎么保真线程安全
加锁synchronized jdk提供的各种锁

synchronized和volatile区别
synchronized是加锁的关键字;我觉得他和volatile没有可比性,倒是可以和reentranceLock比较一下。巴拉巴拉
volatile是java的关键字,是一种轻量级的同步机制,可以保证可见性,防止指令重排序,读写单操作的原子性 ,复合操作不能保证。

volatile能保证线程安全么
不能

DCL为什么要加volatile
防止指令重排序

线程之间常用的通信方式
文件 数据库 mq redis 等外部组件

volitale
锁 共享对象

countDownLatch
cyclicBarrier
semaphore

wait notify

如何优雅的结束一个线程,比如线程在执行下载任务,用户觉得太慢,然后就取消了
调用线程的 interrupt方法,改变线程中的volatile 标志位,线程中需要自己去不断的判断这个 标志位,执行相应的逻辑。

isInterrupted 什么也不改变你,返回当前状态
interrupt 当前状态改为true, 无返回值
interrupted 将当前状态改为false,返回当前状态。对当前线程起作用,因为调用的就是当前线程。
线程相关面试题
中断在join的线程,会立刻抛出异常并将标志位重置为false
中断在sleep的线程,会立刻抛出异常并将标志位重置为false
阻塞状态的线程是不可被终端:没有得到锁的线程,会被挂起的线程,但中断不会抛出异常,会继续执行完下边的逻辑。但join,sleep状态的线程,被中断的时候会立刻抛出异常。

对同一个线程,能否在获取到锁以后继续获取同一个锁
答案是肯定的。JVM允许同一个线程重复获取同一个锁,这种能被同一个线程反复获取的锁,就叫做可重入锁。
由于Java的线程锁是可重入锁,所以,获取锁的时候,不但要判断是否是第一次获取,还要记录这是第几次获取。每获取一次锁,记录+1,每退出synchronized块,记录-1,减到0的时候,才会真正释放锁。

reentrantLock 怎么实现synchronized的wait和notify
conditionn 而且可以有多个condition,这样就能同时唤醒多组线程
reentrantLock.newCondition()
condition.await()
condition.signalAll()

ReadWriteLock的并发情况
解决某些情况(read、read)允许并发的情况。只有在读读的时候是可以并发的,在读写的时候是不能并发的,读写的时候是一种悲观锁。

juc中的读写锁
和上面的定义一样,只有读读的时候是乐观锁

Java 8引入了什么提高读写的性能
在java8中没有找到ReadWriteLock的实现
StampedLock和ReadWriteLock相比,改进之处在于:读的过程中也允许写入!这样一来,我们读的数据就可能不一致,所以,需要一点额外的代码(校验版本号,如果版本号被修改,那么使用悲观锁排队)来判断读的过程中是否有写入,这种读锁是一种乐观锁。

父停子停
守护线程,守护线程不能持有需要关闭的资源(如打开文件等),不会报错,但可能导致文件缺失,会不会内存泄露看引用链条

父等子停
join

怎么获取线程结果
implements Callable
通过Future获得异步执行结果时,要么调用阻塞方法get(),要么轮询看isDone()是否为true
CompletableFuture Java 8开始引入
改进了Future,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法

三个线程 谁先结束,主线程结束返回
completureFulture

怎么解决一个线程中,横跨若干方法调用,局部变量的保存。比如一个线程从tomcat controller service dao
threadLocal 可以存储一个线程的局部变量。一个线程从tomcat controller service dao,不用一层一层的传值,可以将他们的共同变量,放到这个这个线程的threadLocal ,这个线程还是这个线程,走到那都可以从中拿出共享变量来

线程报错怎么排查
一般有问题的线程 cpu的使用率会很高
top -H 看那个进程占用的 cpu比较多
top -Hp id 查看进程中那个线程占用的资源比较多
printf “%x\n” id 得到此线程的十六进制
jstack process-id | grep x-id

execute submit提交任务的区别
execute是定义在Executor接口中的,只能接受Runnable对象。submit是定义在ExecutorService中的,ExecutorService继承自Executor,他有三个重载方法,分别可以接收Runnable对象;Runnable对象和返回泛型;回调方法。
execute是没有返回值的,submit有返回值future。
如何获得线程运行异常
https://zhuanlan.zhihu.com/p/170320272
executor会自动打印堆栈信息,但这个是我们不可控的。
submit默认是不会输出异常的,使用返回值的get可以得到,future.get(),但这个是阻塞的 ,无法快速执行下面的逻辑。
设置Executors.defaultThreadFactory()的setUncaughtExceptionHandler的逻辑

如何配置线程数
cpu密集型任务 cpu核数个线程
io密集型 cpu核数 * 10 个

问题
https://zhuanlan.zhihu.com/p/270606355

上一篇:Java


下一篇:【Java面试题总结 3】Java多线程篇,java线程池原理图