JAVA多线程高并发面试题总结

1,什么是线程?线程和进程有什么区别?

答:线程是程序执行的最小执行单位,进程是资源分配的最小单位,一个进程就是一个应用程序,系统会为该进程分配资源空间,当多用户并发请求的时候,为每个用户创建一个进程显然是不可能的资源开销太大,就开辟了线程,线程速度比较快,线程之间共享进程之间的内存资源。

2,如何在Java中实现线程?

答: 继承Thread类

实现Runnable接口、

实现Callable接口通过FutureTask包装器来创建Thread线程、

使用ExecutorService、Callable、Future实现有返回结果的多线程。

其中前两种方式线程执行完后都没有返回值,后两种是带返回值的。

3,Java 关键字volatile 与 synchronized 作用与区别?

答:线程有几个特性

原子性:不被其他线程中断

可见性:执行结果其他线程可以看到

顺序性:保证线程操作的执行顺序

volatile 可作用于变量范围比较小, synchronized可作用于方法变量以及类和代码块。

volatile 修饰的变量的更改在线程未结束的时候可以被其他线程读取,修改后立马刷新到主存当中不保证原子性, synchronized则保证线程执行完成后变量结果值才可见保证了原子性和可见性与顺序性。

4,有哪些不同的线程生命周期?

答:新建状态

就绪状态

运行状态

阻塞状态

终止状态

5,你对线程优先级的理解是什么?

答:每一个线程都是有优先级的,一般来说,高优先级的线程在运行时会具有优先权,但这依赖于线程调度的实现,这个实现是和操作系统相关的(OSdependent)。可以定义线程的优先级,但是这并不能保证高优先级的线程会在低优先级的线程前执行。线程优先级是一个int变量(从1-10),1代表最低优先级,10代表最高优先级。

6,什么是死锁(Deadlock)?如何分析和避免死锁?

答:死锁是两个以上的线程一直进行阻塞的状态,解决死锁,查找状态为blocked的线程和对应的资源id,并找出对应的资源id,根据资源id可以知道那些线程已经拥有这个对象锁。

7,什么是线程安全?Vector是一个线程安全类吗?

答:对于多线程操作,和多个单独线程同时操作产生得结果一样,Vector类中好多方法是用Synchronized修饰的,但是也有remove 方法和 contains等几个方法不是用Synchronized修饰的这样就需要在业务代码块中添加同步锁,所以准确的不能直接说Vector类是线程安全类,但是普遍的都认为这个类是线程安全的还有拿来和arraylist比较。

8,Java中如何停止一个线程?

答:之前有stop 这种暴力的停止现在已经不使用了,容易造成一些数据的不一致,后来就使用Thread.interrupt(),这个方法在使用的时候直接调用并不能终止线程,需要判断是否终止然后进行业务处理才生效。

9,什么是ThreadLocal?

答:线程的私有变量,为每一个线程提供一个变量副本,也就不会出现高并发问题。

10,Sleep()、suspend()和wait()之间有什么区别?

答:Sleep()固定时间后主动唤醒,suspend()已经废弃的暂停方法被resumen唤醒,wait()被notifywai唤醒

11,什么是线程饿死,什么是活锁?

答:饿死:线程没有被合理的分配资源,无限期的等待

      活锁:线程自己都认为自己的优先级别不够高,导致都不尽兴资源的利用,线程都在等待对方先执行。

12,什么是Java Timer类?如何创建一个有特定时间间隔的任务?

答:Timer是一种线程设施,用于安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行,可以看成一个定时器,可以调度TimerTask。TimerTask是一个抽象类,实现了Runnable接口,所以具备了多线程的能力。一个Timer可以调度任意多个TimerTask,它会将TimerTask存储在一个队列中,顺序调度,如果想两个TimerTask并发执行,则需要创建两个Timer。

13,什么是线程池? 为什么要使用它?

答:用来管理多线程任务中对线程的管理,创建线程,运行,和销毁,如果客户端访问量过大,那么创建线程和销毁线程将是一笔很大的开销,所以有了线程池,可以将运行完成的线程暂时放在线程池中,当新的请求过来的时候,直接用就可以,当先线程池也不易过多,

14,多线程中的忙循环是什么?

答:  忙循环就是程序员用循环让一个线程等待,不像传统方法wait(), sleep() 或 yield() 它们都放弃了CPU控制,而忙循环不会放弃CPU,它就是在运行一个空循环。这么做的目的是为了保留CPU缓存,在多核系统中,一个等待线程醒来的时候可能会在另一个内核运行,这样会重建缓存。为了避免重建缓存和减少等待重建的时间就可以使用它了。

15,Thread 类中的start() 和run() 方法有什么区别?

答:1,start 是用来启动线程的,run()则是运行线程的 

2,start 在一个线程中只能调用一次,而run则可以多次调用

3,查看Thread类的源码会发现start 有synchronized的修饰,可见这个方法是多线程的。

16,在多线程中,什么是上下文切换?

答:cpu通过给每个线程分配时间片来存储和回复线程的状态,一般因为时间非常短,所以cpu通过不断地切换线程,让我们感觉多个线程是同时执行的,一般时间片为几十毫秒。

17,Java中的volatile 变量是什么?

答:volatile只作用与变量

1,volatile修饰的变量会及时的刷新到共享内存中,保证线程每次获取都是最新的

2,volatile修饰的变量禁止了指令重排序。

18,Java中堆和栈有什么不同?(相对于线程来说)

答:创建的对象是在堆中,是线程内存共享的区域,而栈中是是线程私有的区域生命周期随着线程的消亡而消亡,为来提高运行效率会重堆中复制一份变量到栈中,运行完成后再刷新到主内存中。

19,什么是线程池? 为什么要使用它?

答:创建线程是需要时间和资源的,如果任务来了才去创建线程,显然是不对的,我们会在程序启动的时候事先放入几个线程,当有任务调用的时候就直接去链接线程池中的线程,任务结束再放回线程池,线程不易创建太多,线程之前的切换也很耗费资源。

20,死锁是什么?如何避免死锁?

答:死锁是多个线程对资源争夺互相等待的过程。

如何避免死锁要知道死锁产生有4个条件

1,资源互斥:多个进程挣夺同一个资源

2,请求与保持:对已经持有的资源再没有完成线程请求不释放

3,不剥夺:进程已经使用资源在未使用完之前不尽兴剥夺

4,循环等待:若干个进程之间形成头尾相接循环等待的关系

避免死锁就要避免循环等待条件的产生,设置资源标识位以及执行顺序等。

21,Thread类中的yield方法有什么作用?

答:让当前正在运行的线程回到就绪状态,让出cpu,等待cpu的再次调度。

22,Java中notify 和 notifyAll有什么区别?

答:notify是唤醒等待池中的某一个线程但是不指定是那个,notifyAll是唤醒等待池中的所有线程进入锁池中竞争对象。

23,Java中interrupted 和 isInterruptedd方法的区别?

答:我们说三个

interrupt() 向当前调用者线程发出中断信号

isinterrupted() 查看当前中断信号是true还是false

interrupted() 是静态方法,查看返回当前中断信号并将中断信号复位

任何抛出InterruptedException异常的方法都会将中断状态清零

24,Java多线程中调用wait() 和 sleep()方法有什么不同?

答:sleep()是Thread的静态方法,线程调用此方法会让线程暂时放弃cpu资源供其他线程使用,但是不会释放对象锁,时间到后会自动苏醒,但是不会立即执行线程,需要捕获异常

wait()方法必须放在同步控制方法或者同步语句块中使用,会暂时放弃对象锁,然后此线程进入阻塞状态,等notify()方法讲起唤醒进入待运行状态。

25, 有三个线程T1,T2,T3,怎么确保它们按顺序执行?

答:启动某个线程的时候分别加入join()方法,T3调用T2然后T2调用T1,利用单线程池法

26, 如何创建守护线程?

答:在启动线程之间设置线程的属性

publicclass DaemonThread {

    publicstaticvoid main(String[] args) {

        Thread daemonThread =newThread(new Runnable() {

            @Override

            publicvoid run() {

            }

        });

        //设置守护线程daemonThread.setDaemon(true);

        daemonThread.start();

    }

}

27,什么是线程调度器(Thread Scheduler)和时间分片(Time Slicing)?

答:线程调度器是一个操作系统服务,它负责为Runnable状态的线程分配CPU时间。一旦我们创建一个线程并启动它,它的执行便依赖于线程调度器的实现。

  时间分片是指将可用的CPU时间分配给可用的Runnable线程的过程。分配CPU时间可以基于线程优先级或者线程等待的时间。线程调度并不受到Java虚拟机控制,所以由应用程序来控制它是更好的选择(即最好不要让你的程序依赖于线程的优先级

28,什么是ThreadLocal?

答:线程有共享变量,但是不安全的需要用到锁的机制来维护,那么有的对象不需要锁,而且单个线程自己使用,不需要共享,那么ThreadLocal就是线程的局部本地变量,为每个线程私有。

29,Java线程池中submit() 和 execute()方法有什么区别?

答:两个方法都可以向线程池中提交任务, execute()方法定义在Executor为void修饰的方法,submit() 方法定义在ExecutorService中有返回值Future对象,可以对Future对象的get方法获取到返回执行结果。

30,Java中Runnable和Callable有什么不同?

答:都代表那些在不同线程中执行的任务,Runnable从jdk1.0就有,Callable从jdk5.0有,callabel的call()方法可以返回执行结果Futuret并抛出异常

31,什么是FutureTask?

答:1 FutureTask概念

FutureTask一个可取消的异步计算,FutureTask 实现了Future的基本方法,提空 start cancel 操作,可以查询计算是否已经完成,并且可以获取计算的结果。结果只可以在计算完成之后获取,get方法会阻塞当计算没有完成的时候,一旦计算已经完成,那么计算就不能再次启动或是取消

一个FutureTask 可以用来包装一个 Callable(一个有返回值的runnable) 或是一个runnable对象。因为FurtureTask实现了Runnable方法,所以一个 FutureTask可以提交(submit)给一个Excutor执行(excution).

2 FutureTask使用场景

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。

你可能感兴趣的:(JAVA多线程高并发面试题总结)