线程面试题

1、进程、线程和协程的区别
进程:是资源分配的最小单位,操作系统会给进程分配cpu和内存资源等。进程可以说是程序的一次运行,而一个进程可以有多个线程
线程:是操作系统调用执行的最小单位,同时一个线程可以有多个协程
一个进程由系统给分配资源,然后进程中的多个线程共享该进程的所有资源。线程不能脱离进程而存在。
协程:比进程更加轻量级的存在。协程不是被操作系统内核所管理的,而完全是由程序所控制的。线程之间的切换需要消耗资源,但是协程之间的切换不需要消耗资源
2、典型的调度算法
(1)FIFS算法(先来先服务调度算法)
就是那个那个进程先进来,操作系统就先执行那个进程,这就是先来先服务
(2)SJF算法(短作业优先调度算法)
从等待队列中选择一个或者若干个估计运算时间最短的作业,将他们调入内存运行。
缺点:1)对长作业不利。
2)没有考虑到作业的优先级。
3)由于作业的长短只根据用户所提供的估计执行时间而定的,而用户又可能会有意或无意的缩短其作业的估计运行时间,致使该算法不一定能真正做到算作业优先调度。
4) 注意:SJF调度算法的平均等待时间、平均周转时间最少。
(3)优先级调度算法
按照优先级的高低,来选择调入进程调入内存运行。
(4)时间片轮转
指定每个进程的运行时间,如果在这个时间内,进行没有完成,将进程进入就绪态,等到下一次轮到了在继续执行。
3、线程有哪些状态
(1)初始状态(new):新创建一个线程对象,但是还没有调用start();
(2)运行状态(runnable):java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行状态”。线程创建之后,其他线程(比如main线程)调用该对象的start()方法,改状态的线程位于可运行的线程池中,等待被线程调度,获取cpu使用权,此时处于就绪态,就绪态的线程获取cpu时间片后变成运行中状态。
(3)阻塞状态(blocked):线程没有获得锁资源进入阻塞态。
(4)等待(waiting):进入该状态的线程需要等待其他线程做出一些特定动作(通知或者中断)
(5)超时等待(timed_waiting):该状态不同于waiting,他可以在指定的时间后自动返回
(6)终止(terminated):表示该线程已经执行完毕。
在这里插入图片描述
注意:调用start()进入的是就绪态而不是running状态。
4、线程状态的转换
Stop(),suspend(),yield(),notify(),sleep(),start(),run(),wait(),join(),notifyAll()

Start():	启动线程,实际上就是请求Jvm运行相应的线程,而这个线程什么时候能够运行,就是由线程调度器决定的了。start()调用结束不代表线程已经开始运行了,只是请求运行了。如果sleep时间没有到,可以使用interrupt()来强行打断。
run():	相当于线程执行的入口。由jvm在运行相应线程时直接调用,而不是由应用代码调用。
sleep()	用于暂定当前线程,线程进入timed_waiting状态,不会释放锁资源,只会阻塞线程,等到指定的sleep时间过去之后,会自动回复成运行状态,sleep的线程,会给优先级比自己低的线程运行的机会。调用这个方法要处理InterruptedException异常。
wait():	使一个线程处于阻塞态。同时会释放锁资源,wait使用时必须先获取对象锁,即必须在synchronized修饰的代码中使用。同时,使用wait()的线程,必须其他线程通过notify()或者notifyAll()将其从等待池中放出来。
yield()	用于暂定当前线程,线程使用yield()之后进入就绪态,yield让出资源后,只能让同优先级或者更高优先级的线程使用。所以执行了yield()的线程很有可能重新被执行。
join()	等待调用join()的线程结束之后,程序才能继续执行,一般用于等待异步线程执行完结果之后才能继续运行的场景。
stop()	用于终止所有未结束的方法,包括run(),当一个线程停止以后,会释放所有锁,会导致对象处于不一致的状态
suspend()	suspend不会破坏对象。但是,如果你用一个suspend挂起一个有锁的线程,那么在锁恢复之前将不会被释放。如果调用suspend的方法线程试图取得相同的锁,程序就会死锁。

5、等待池和锁池
锁池:
锁池的本质就是假设线程 A 已经拥有了某个对象(不是类)的锁,而其它线程 B、C 想要调用这个对象的某个 synchronized 方法(或者块),由于这些 B、C 线程在进入对象的 synchronized 方法(或者块)之前必须先获得该对象锁的拥有权,而恰巧该对象的锁目前正被线程 A 所拥有,所以这些 B、C 线程就进入了该对象的锁池,这就是锁池。
等待池:
等待池的本质就是假设线程 A 调用了某个对象的 wait() 方法,线程 A 就会释放该对象的锁(因为 wait() 方法必须在 synchronized中使用,所以执行 wait() 方法前线程 A 已经持有了该对象的锁),同时线程 A 就进入到了该对象的等待池中。如果此时线程 B 调用了相同对象的 notifyAll() 方法,则处于该对象等待池中的线程就会全部进入该对象的锁池中去准备争夺锁的拥有权。而如果此时线程 B 调用的是相同对象的 notify() 方法,则仅仅会有一个处于该对象等待池中的线程(随机)进入该对象的锁池中去准备争夺锁的拥有权。

6、线程的同步和异步
如果系统中存在临界资源(资源数量少于竞争资源的线程数量的资源),例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就必须进行同步存取(数据库操作中的排他锁就是最好的例子)。当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。事实上,所
谓的同步就是指阻塞式操作,而异步就是非阻塞式操作
7、Java中有几种生成线程的方法
两种:①实现Runnable接口,重写run()
②继承Thread类
8、Synchronize的使用
锁住代码块,锁住类的实例方法,锁住类(或者静态方法)
(1)synchronize锁住代码块时,这需要取得指定对象的锁才能够进入代码块。
(2)synchronize锁住实例方法时,需要获取当前实例对象的锁
(3)synchronize锁住类或者静态方法时,需要获得当前类的锁

9、CountDownLatch和CyclicBarrier的区别
CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:
CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;
而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;
另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。
CountDownLatch和CyclicBarrier都有让多个线程等待同步然后再开始下一步动作的意思,但是CountDownLatch的下一步的动作实施者是主线程,具有不可重复性;而CyclicBarrier的下一步动作实施者还是“其他线程”本身,具有往复多次实施动作的特点。
10、多线程中——并行与并发的区别
并行:在同一时刻,有多条指令在多个处理器上同时执行。
并发:在同一时刻只能有一条指令执行,但是多个线程指令被快速的轮换执行。所以只是将一段时间分成若干段,让多个进程快速交替的执行。
11、线程池的使用

12、死锁的产生
四个必要条件:
(1)不可抢占:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。
(2)循环等待:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求
(3)保持与请求:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
(4)互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。

13、怎么预防死锁,怎么避免死锁
预防死锁:破坏四个必要条件中的一个,或几个,就可以预防死锁
避免死锁:典型的是——银行家算法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值