• Java面试中的常问的多线程问题



    目录

    1.什么是进程

    2.什么是线程

    3.什么是并发

    4.什么是并行

    5.什么是吞吐量

    6.多线程带来的哪些好处

    7. 高并发多线程注意的问题有哪些

    8.线程不安全的理解

    9.实现多线程的三种方式

    10 什么是FutureTask

    11. 如何理解中断线程

    12.线程的生命周期有哪些

    13.Thread.start()和Thread.run()区别

    14.守护线程是什么

    15.synchronized有什么作用

    16.Lock和synchronized区别

    17.wait(),notify(),notifyall() 的作用是什么

    18. 什么是悲观锁、乐观锁

    19. 说说对 volatile的理解



     

    1.什么是进程

           进程是操作系统进行资源分配的最小单位,资源包括:CPU,内存空间,磁盘IO等。进程和进程之间是相互独立的

    2.什么是线程

          线程是CPU的最小调度单位,它比进程更小,线程共享一个进程下的资源,可以相互通信相互影响

    3.什么是并发

         在操作系统中,一个时间段内,有几个程序都处于启动到运行完毕,并且这几个程序都是在同一个处理机上运行  ,并发是指再一段时间内宏观上多个程序同时运行,多个任务抢占资源

    4.什么是并行

         当系统有一个以上的CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程。两个进程互不抢占资源,这种方式成为并行   。并行是指同一个时刻,多个任务真实运行互不影响,即多个任务不互相抢占资源

    5.什么是吞吐量

            吞吐量指对网络 、设备、端口、虚电路或其他设施,单位时间内成功的传送数据的数量,网络吞吐量是指某个时刻,网络中两个节点间提供给网路应用的声音带宽,在没有帧丢失的情况下,设备能够接受的最大速率。

    6.多线程带来的哪些好处

    1)充分利用CPU的资源

           市面上都是多CPU并支持多线程并发机制的,如果线程只在一个CPU核心中的一个线程中跑, 那么就浪费了CPU资源。就如同:计算机支持多个“车道”同时通车,如果你的程序只使用一个“车道”那么其他车道就属于闲置状态

    2)加快相应用户的时间

          当服务器收到一条请求后,多个线程再加不同的资源或者分别处理不同的任务, 那么势必会减少相应的速度,相应所读提高了,用户体检就会更好

    3)将代码模块化异步化简单化

           界面加载数据的时候可以分不同模块同时加载,每一个模块有可以独立设计

    7. 高并发多线程注意的问题有哪些

    1)线程之间的安全问题

            在同一个进程里的线程共享进程资源,那么就需要考虑资源使用的安全,比如:一个全局变量多个线程同时执行写操作,那么会出现程序问题,此时线程不安全。 因此,需要考虑线程同步保证线程安全

    2)线程之间的死锁问题

            Java为了解决线程之间的安全问题引入了锁机制。 如果不同的线程等待根本不可能释放的锁导致工作无法完成,我们称这种现象为线程死锁

    8.线程不安全的理解

            当多个线程同时操作一个数据结构的时候,产生了相互修改和串行的情况,没有保证数据的一致性,通常称作这种代码未“线程不安全”。实际工作中,特别是Web项目Service和servlet一般都是单例的,在共享变量的情况下很容易出现线程不安全。

    实现线程安全常见三种方法

    •         不使用单例,改为多实例
    •         使用java.util.concurrent下面的类库
    •         使用锁机制synchronized,lock等方式

    9.实现多线程的三种方式

    1)继承Thread覆盖run方法

    1. public class MyThread extends Thread {
    2. @Override
    3. public void run() {
    4. // TODO Auto-generated method stub
    5. }
    6. }

    2)实现Runable接口

    1. public class MyThread implements Runnable {
    2. @Override
    3. public void run() {
    4. // TODO Auto-generated method stub
    5. }
    6. }

    3)实现Callable接口

    1. import java.util.concurrent.Callable;
    2. public class MyThread implements Callable{
    3. @Override
    4. public Object call() throws Exception {
    5. // TODO Auto-generated method stub
    6. return null;
    7. }
    8. }

    10 什么是FutureTask

    •  FutureTask是一个异步运算的任务,FutureTask里面可以可以传入Callable实现类作为参数,可以对异步运算任务的结果进行等待获取,判断是否已经完成,取消任务等操作。
    • 只有当结果完成之后才能取出,如果尚未完成get方法将堵塞。
    • 一个Future对象可以调用Callable和Runable的对象进行包装,由于FutureTask也是Runnable接口的实现类,所以FutureTask也可以放入线程池中
       

    11. 如何理解中断线程

          Java线程中断是一种协作机制,中断并不能直接终止另一个线程,而需要被中断的线程自己处理,简单理解为线程有个boolean标识代表是否有中断请求,如果有,线程会在何时的时候自己处理中断请求,
           例如:线程T1想中断T2, 只需要在T1中将T2的中断表示设置为true,然后T2可以选择在合适的时候处理中断请求,也可能不理会该请求

    1. //测试当前线程是否已经中断
    2. public static boolean interrupted()
    3. //测试线程是否已经中断,线程的中断状态不受该方法影响
    4. public boolean isInterrupted();
    5. //设置线程中断,是唯一能将中断状态设置为true的方法
    6. public void interrupt()

            

    12.线程的生命周期有哪些

    线程的生命周期一共有5个状态:new,runable,running,blocked,dead

    13.Thread.start()和Thread.run()区别

    • start方法的作用是启动一个新线程,真正实现多线程,新线程会执行相应的run()方法。start()不能被重复调用。

    • run方法就和普通的成员方法一样,可以被重复调用。单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程!

    14.守护线程是什么

           守护线程可以理解为后台运行的线程,进程结束,守护线程就会结束,不需要手动的取关心和通知其状态,在JVM的垃圾回收、内存管理的线程都是守护线程,还有比如数据库链接池的线程等

           守护线程和普通线程没有太大区别,只需要调用线程对象setDeamon(true)方法将线程标记为守护线程

    1. //需要在线程启动前声明
    2. public final void setDeamon(boolean on)

    15.synchronized有什么作用

          synchronized是Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行这段代码,解决多线程“时序性问题” Synchronized是在JVM成名实现的,当代码出现异常的时候JVM自动释放,当只有少量竞争的时候,Synchronaized是很好的通用锁实现

    • 修饰方法声明时使用,放在范围操作符之前, 返回类型声明之后
    • 修饰代码块,使用synchronized(Object)指定加锁对象,Object可以是任意对象获参数

    16.Lock和synchronized区别

    • Lock使用起来比较灵活,但是必须有释放锁动作
    • Lock必须手动释放锁,而synchronized不需要手动释放和开启锁
    • Lock只适用代码块锁,而synchronized对象之前是互斥关系

    17.wait(),notify(),notifyall() 的作用是什么

    • wait()     方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出并进入等待队列,等待被再次唤醒
    • notify()   方法可以随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知1个线程
    • notifyAll()方法可以使所有正在等待队列中等待同一共享资源的全部线程从等待状态退出,进入可运行状态,优先级最高的那个线程最先执行

    18. 什么是悲观锁、乐观锁

    • 悲观锁:假设会发生并发冲突,屏蔽一切可能违反数据完整性的操作
    • 读取悲观锁:在读取之前一定要判断,数据有没有正在被更改
    • 乐观锁:假设不会发送并发冲突,只是在提交操作的时候检查是否违反数据完整性
    • 读取乐观锁:在读取之前不需要判断数据一致性,直管读自己的

    19. 说说对 volatile的理解

    • volatile主要作用是让被修饰的变量在多个线程间可见, 变量被volatile修饰后,每次读取变量的时候都从它的内存地址中读取
    • volatile只提供了内存可见,而没有提供原子性,因此如果使用volatile做高并发的安全机制是不可靠的


  • 相关阅读:
    ssm技术
    JAVA毕设项目客服管理系统(Vue+Mybatis+Maven+Mysql+sprnig+SpringMVC)
    慈恩寺
    nginx多文件组织
    智慧公厕建设的好处
    《统计学习方法》啃书手册|核函数构成希尔伯特空间的步骤详解
    一文搞懂UART通信协议
    10.Tomcat,Servlet
    nsight computer运行失败问题
    K8s: 持久化存储之卷, NFS卷
  • 原文地址:https://blog.csdn.net/Beijing_L/article/details/125858034