java面试题_多线程篇
1多线程基础知识
1.1线程与进程的区别
线程隶属于进程,可以理解为一个cpu里有多个进程 ,进程里有多个指令按顺序可以执行多个线程。
二者对比
进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务
不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间
线程更轻量,线程上下文切换成本一般上要比进程上下文切换低(上下文切换指的是从一个线程切换到另一个线程)
1.2并行与并发的区别
对于单核cpu而言
单核CPU下线程实际还是串行执行的
操作系统中有一个组件叫做任务调度器,将cpu的时间片(windows下时间片最小约为 15 毫秒)分给不同的程序使用,只是由于cpu在线程间(时间片很短)的切换非常快,人类感觉是同时运行的 。
总结为一句话就是: 微观串行,宏观并行
一般会将这种线程轮流使用CPU的做法称为并发(concurrent)
多核cpu而言
现在都是多核CPU,在多核CPU下
并发是同一时间应对多件事情的能力,多个线程轮流使用一个或多个CPU
并行是同一时间动手做多件事情的能力,4核CPU同时执行4个线程
1.3线程创建的方式有哪些
共有四种方式可以创建线程,分别是:
继承Thread类
实现runnable接口
实现Callable接口
线程池创建线程
继承Thread类
实现runnable接口
实现Callable接口
线程池创建线程
1.4runnable 与callable 有什么区别
Runnable 接口run方法没有返回值
Callable接口call方法有返回值,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果
Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛
1.5线程包括那些状态,状态之间是如何变化的
新建(NEW)、可运行(RUNNABLE)、阻塞(BLOCKED)、等待( WAITING )、时间等待(TIMED_WALTING)、终止(TERMINATED)
创建线程对象是新建状态
调用了start()方法转变为可执行状态
线程获取到了CPU的执行权,执行结束是终止状态
在可执行状态的过程中,如果没有获取CPU的执行权,可能会切换其他状态
如果没有获取锁(synchronized或lock)进入阻塞状态,获得锁再切换为可执行状态
如果线程调用了wait()方法进入等待状态,其他线程调用notify()唤醒后可切换为可执行状态
如果线程调用了sleep(50)方法,进入计时等待状态,到时间后可切换为可执行状态
1.6在java中wait和sleep方法的不同
如果线程调用了wait()方法进入等待状态,其他线程调用notify()唤醒后可切换为可执行状态
如果线程调用了sleep(50)方法,进入计时等待状态,到时间后可切换为可执行状态
1.7新建三个线程,如何保证它们按顺序执行
可以使用线程中的join方法解决
join() 等待线程运行结束
例子:
t.join()
阻塞调用此方法的线程进入timed_waiting
直到线程t执行完成后,此线程再继续执行
1.8notify()和 notifyAll()有什么区别
notifyAll:唤醒所有wait的线程
notify:只随机唤醒一个 wait 线程
1.9线程的 run()和 start()有什么区别
start(): 用来启动线程,通过该线程调用run方法执行run方法中所定义的逻辑代码。start方法只能被调用一次。
run(): 封装了要被线程执行的代码,可以被调用多次。
1.10如何停止一个正在运行的线程
有三种方式可以停止线程
使用退出标志,使线程正常退出,也就是当run方法完成后线程终止
使用stop方法强行终止(不推荐,方法已作废)
使用interrupt方法中断线程
打断阻塞的线程( sleep,wait,join )的线程,线程会抛出InterruptedException异常
打断正常的线程,可以根据打断状态来标记是否退出线程
2线程中并发安全
2.1synchronized关键字的底层原理
Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】
它的底层由monitor实现的,monitor是jvm级别的对象( C++实现),线程获得锁需要使用对象(锁)关联monitor
在monitor内部有三个属性,分别是owner、entrylist、waitset
其中owner是关联的获得锁的线程,并且只能关联一个线程;entrylist关联的是处于阻塞状态的线程;waitset关联的是处于Waiting状态的线程
synchronized关键字的底层原理-进阶
评论