多线程面试题

多线程的面试题

1.什么是活锁、饥饿、无锁、死锁?

**无锁:**没有对资源进行锁定,所有的线程都可以对同一资源进行修改,但是同时只有一个线程修改成功。
**饥饿:**当线程由于种种原因一直没有抢占到cpu执行权时形成饥饿,只有当其它线程执行完后释放资源可能执行
**死锁:**当线程中互相抢占对方的锁资源,并且都等待对方释放锁,成一种假死状态。
**活锁:**与死锁相反,线程之间相互谦让,都不执行。

2.线程和进程的区别是什么?

进程:程序在运行时执行的一个任务,是操作系统在资源管理上的最小单位。
线程:是进程的执行单元,对CPU资源抢占的最小单位。

3.Java 实现线程有哪几种方式?

四种,继承Thread类,实现Runnable接口、实现Callable接口,线程池(ThreadPoolExecutor)。

4.启动线程方法 start和 run有什么区别?

启动run方法是调用run方法,如果启动start方法会启动一个线程。

5.怎么终止一个线程?如何优雅地终止线程?

线程的普通终止有两个方式,要么线程执行完毕,要么线程抛出异常。
我们还可以调用stop()方法关闭线程,但是这样不优雅,而且该方法已进过时。

我们要想优雅的终止线程,可以通过:
①标记为设定是否要终止线程。
②使用Interrupt方法。

6.一个线程的生命周期有哪几种状态?它们之间如何流转的?

创建,就绪,运行,阻塞,终止
新建状态(New):至今尚未启动的线程的状态。线程刚被创建,但尚未启动。如:Thread t = new MyThread();

就绪状态(Runnable):当调用线程对象的start()方法,线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。

阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

1)等待阻塞—位于对象等待池中的阻塞状态(Blocked in object’s wait pool):当线程处于运行状态时,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中,这涉及到“线程通信”的内容。

2)同步阻塞 --位于对象锁池中的阻塞状态(Blocked in object’s lock pool):当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中。

3)其他阻塞状态(Otherwise Blocked):当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态。线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

7.线程中的 wait和 sleep方法有什么区别?

当使用wait时,必须在同步代码块或者同步方法中使用,而sleep在任何地方都能使用
wait在java.long.Object类中定义,sleep在java.long.Thread包中定义。
wait使用是不需要主动捕获异常,sleep需要捕获异常。
wait可以释放锁,sleep不释放锁。
wait不知道等待时间,根据notify、notifyAll来唤醒wait,sleep可以设定时间,时间到后自动变为就绪状态。

8.多线程同步有哪几种方法?

通过Object的wait和notify :线程通信
通过Condition的awiat和signal :通过lock获取condition, 对应synchronized 的 wait和notify
通过SynchronousQueue : SynchronousQueue表示线程安全的队列,使用put和take进行放和取,且只能放一个、取一个
通过同步辅助类CountDownLatch :设定CountDownLatch 然后线程中调用countDown方法进行递减
通过同步辅助类CyclicBarrier :加法器加到一定数量就释放锁

9.多线程有什么用?

我们可以将一个连续时间上做的事情,让它在不影响流程的情况下同时去做,可以提高程序的运行效率,减少等待时间。
可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。

10.多线程之间如何进行通信?

通过wait,notify,notifiyAll进行线程通信
Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,这种方式实现线程间协作更加安全和高效。

11、线程怎样拿到返回结果?

通过callable接口。将callable实现类重写call方法后放入FutureTask构造器中,将FutureTask并传入Thread构造器可通过get()方法获得。

12、violatile 关键字的作用?

violatile 是jvm轻量级的线程同步机制。

  1. 打开多线程之间可见性
  2. 防止指令重新排列
  3. 不可实现原子性
13、新建 T1、T2、T3 三个线程,如何保证它们按顺序执行?

在每个线程中加入判断,当各线程中只有选定的线程可以通过,其他线程都会wait阻塞,指定线程通过后修改下一个线程执行的值。

14、怎么控制同一时间只有 3 个线程运行?

可以通过Semaphore semaphore = new Semaphore(3);实现

public class SemaphoreTest {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);
        for (int i = 1; i <= 20; i++) {
            new Thread(()->{

                try {
                    //获取
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + ":停车");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + ":离开");

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //释放
                    semaphore.release();
                }

            },String.valueOf(i)).start();
        }
    }
}

15、为什么要使用线程池?

线程池提供了一种对线程统一管理的方式,可以减少频繁的线程创建和销毁带来的性能问题。
可以系统化管理,我们可以设定很多参数,根据业务设定合适的参数。
提高线程的相应速度。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值