对象面试官系列之Java并发--面试官看了都说好

2023-12-13 18:08

本文主要是介绍对象面试官系列之Java并发--面试官看了都说好,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.线程的实现

A.实现Runnable接口;多个线程共同完成一个任务

B.实现Callable接口;

与Runnable相比,Callable可以有返回值还可以抛出异常,返回值通过FutureTask进行封装。

FutureTask<String> futureTask = new FutureTask<String>(new CallTest());

new Thread(futureTask).start();

C.继承Thread类。(多个线程分别完成自己的任务)

D.线程池

2.线程状态

进程、线程:新建、就绪、运行、阻塞、终止

3.上下文切换

概念:CPU是通过给每个线程分配时间片并轮转的方式来实现多线程,当前任务在执行完CPU时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换回这个任务时,可以再加载这个任务的状态。任务从保存到再加载的过程就是一次上下文切换

减少上下文切换时间:1.无锁并发编程。多线程竞争锁时会引起上下文切换

2.CAS算法

3.使用最少线程

4.线程死锁

多个线程互相持有对方需要的资源从而被同时阻塞

必要条件:

互斥条件:该资源任意一个时刻只由一个线程占用。

请求与保持条件:一个进程因请求资源而阻塞时,不会释放已获得的资源。

不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。

循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

如何避免:

破坏互斥条件:无法破坏,因为我们用锁本来就是想让他们互斥的。

破坏请求与保持条件:一次性申请所有的资源。

破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。

破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件

如何解除:

1.利用抢占:挂起某些进程,并抢占它的资源,将他分配给其他进程。但应防止某些进程被长时间挂起而处于饥饿状态;

2.利用回滚:让某些进程回退到足以解除死锁的地步,进程回退时自愿释放资源。要求系统保持进程的历史信息,设置还原点;

3.利用杀死进程:强制杀死某些进程直到死锁解除为止,可以按照优先级进行.

如何排查:jstack

5.sleep()和wait()区别

1.sleep()不会释放锁,Thread的静态方法;wait()会释放锁,是object下的方法

2.sleep会自动苏醒;wait()需要别的线程调用同一个对象上的notify()或者notifyAll()方法或者可以使用wait(long timeout)超时后线程会自动苏醒

3.sleep和wait都不会占用cpu资源

6.synchronized关键字

6.1 作用

synchronized关键字保证修饰的代码块和方法同一时间只有一个线程在执行;修饰静态方法和修饰代码块都是对类的class对象加锁(一个类多个对象会阻塞),修饰实例方法是给this对象实例加锁(一个类多个对象不会阻塞);

6.2 底层原理

修饰代码块:使用的是monitorenter和monitorexit指令,其中monitorenter指令指向同步代码块的开始位置,monitorexit指令则指明同步代码块的结束位置。当执行monitorenter指令时,线程会获取对象的监视器(monitor)。当计数器为0则可以成功获取,获取后将锁计数器设为1也就是加1。相应的在执行monitorexit指令后,将锁计数器设为0,表明锁被释放。

修饰方法:synchronized会设置方法的一个标识符,然后获取对象的监视器(monitor)。

6.3 Jdk1.6优化

偏向级锁:

当锁对象第一次被线程获取的时候,使用CAS操作把获取到这个锁的线程的ID记录在对象的对象头之中,出现线程竞争时,CAS会失败,然后升级成轻量级锁

轻量级锁:持有偏向锁的对象会将对象头拷贝一份放在栈帧的锁记录中,然后使用CAS将对象头的轻量级锁指针指向锁记录,成功升级成轻量锁,失败会使用自旋获得锁,自旋到一定次数或者有第三个线程竞争升级成重量级锁

重量级锁:会把除了锁以外的线程都阻塞

锁消除:JVM在编译时会对synchronized中的代码进行扫描,判断是否会逃出去被其它线程访问,会进行锁消除从而减少线程请求锁空间。Stringbuffer

6.4 原子性、可见性、有序性

原子性:lock unlock是原子性的

可见性:加锁时会获取主内存的值到工作内存中,释放锁时会将工作内存的变量同步到主内存中

有序性:锁在同一时刻只能有一个线程获取

6.5 和lock的区别

1.lock需要主动unlock解锁,容易造成死锁;synchronized是自动释放锁

2.lock底层使用AQS实现的,可实现公平锁非公平锁;synchronized是通过字节码控制对象的监视器锁实现,只有非公平锁实现。

7.volatile关键字

可见性:对volatile声明的变量进行写操作时,JVM就会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存,然后由于缓存一致性协议,其他处理器的会通过嗅探检测到自己缓存对应的内存地址被修改,就会将当前自己的缓存设置成失效

伪共享问题:

缓存行里不止一个变量,处理器a对变量a修改,那么处理器b要等处理器a提交缓存后,再从主存读取数据,最后才能对变量b进行修改

有序性:volatile读操作会在后面插入一个loadload和loadStore屏障,防止下面的普通读写操作与volatile读操作指令重排序;volatile写操作会在前面插入一个storestore屏障,防止前面普通写操作与volatile写操作重排序,会在后面插入一个storeload屏障,防止后面的volatile读写操作

8. ThreadLocal

ThreadLocal有一个静态内部类ThreadLocalMap。ThreadLocalMap为每一个线程维护了一个数组,数组下标为threadloca对象的hashcode与数组长度取模,值为变量的值;开放地址法解决hash冲突

内存泄漏问题:ThreadLocalMap对threadlocal是弱引用,对value是强引用,value就不会被GC,会造成内存泄漏,解决方法:threadlocal使用完后调用一下remove方***清掉key为null的方法)

9. 线程池

9.1 线程池的创建

ThreadPoolExecutor()

corePoolSize:线程池核心线程大小,最小同时运行的线程数量

CPU密集型:线程个数为CPU核数

IO密集型:线程个数为CPU核数的两倍

maximumPoolSize:线程池最大线程数量,超过就不再创建新线程

workQueue:当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中:

A.ArrayBlockingQueue:数组实现的有界阻塞队列,按照先进先出的顺序进行排序

B.LinkedBlockingQueue:链表实现的阻塞队列,若其构造时指定大小是无界队列;不指定大小,其大小有Integer.MAX_VALUE来决定是无界队列。其所含的对象是先进先出顺序排序的。

C.PriorityBlockingQueue:支持优先级的无界阻塞队列,可以指定排序方法或采取自然顺序升序排列

D.SynchronizedQueue:不存储元素的阻塞队列,插入操作前必须等到另一个溢出操作

keepAliveTime:当线程池中的线程数量大于corePoolSize的时候,空闲线程等待销毁的时间;

unit : keepAliveTime 参数的时间单位。

threadFactory :创建新线程时使用的工厂,可用来设置线程名。

Handler:饱和策略

A. 丢弃任务,抛出异常(默认)

B. 丢弃任务

C. 丢弃队列中最早的任务

D. 用线程池所在线程执行任务

9.2 线程池的执行:

9.3 任务的提交

execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;

submit()方法用于提交需要返回值的任务。线程池会返回一个 Future 类型的对象,通过这个 Future 对象可以判断任务是否执行成功

9.4 线程池的关闭

逐个调用线程的interrupt方法:设置线程的中段标志位,等待线程被阻塞时抛出异常并退出阻塞状态

shutdown():正在执行的任务会继续执行下去,没有被执行的则中断

shutdownNow():正在执行的任务则被停止,没被执行任务的则返回

9.5 常见的线程池

1.FixedThreadPool

使用LinkedBlockingQueue无界队列,核心线程大小和 最大线程大小被设置为同一个值,运行中的FixedThreadPool不会拒绝任务,在任务比较多的时候会导致OOM(内存溢出)。

2.SingleThreadExecutor

使用无界队列(LinkedBlockingQueue),corePoolSize 和 maximumPoolSize 都被设置为 1,也会导致OOM

3.CachedThreadPool(缓存线程池)

使用不存储元素的阻塞队列(SynchronousQueue),corePoolSize 被设置为0,maximumPoolSize 被设置为 Integer.MAX.VALUE,先寻找空闲线程,有就把任务交给空闲线程执行,否则新建线程

4.newScheduledThreadPool

10.AQS(队列同步器)

有一个volatile的int变量表示同步状态值,还有一个双向队列完成资源获取线程的排队工作。

同步器包括一个头节点引用和一个尾节点引用;当前线程获取同步状态失败时,会被构造成一个节点加入队列中,并用CAS将尾节点引用指向节点。

1.ReentrantLock

可重入式:获取锁时会判断当前线程是否占据锁,然后增加同步状态值,释放锁时减小同步状态值,同步状态值为0时才彻底释放

非公平锁(默认):先CAS获取锁,获取失败再判断锁是否被释放,如果被释放就再次CAS获取锁,否则加入双向队列中。加入队列后会自旋判断前驱节点是不是首节点,然后获取同步状态

公平锁:如果当前是无锁状态,会先判断自己是否是头结点引用,如果是CAS获取锁,否则加入双向队列中;加入队列后会自旋判断前驱节点是不是首节点,然后获取同步状态

2.Semaphore(信号量)

初始化同步状态值,获取到资源时状态值减1,状态值为0时需要等待

3.countDownLatch

是通过一个计数器来实现的,计数器为自己设定的值,每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,等待的线程恢复运行;

4.CyclicBarrier(同步屏障)

在CyclicBarrier类的内部有一个计数器,每个线程在到达屏障点的时候都会调用await方法将自己阻塞,此时计数器会减1,当计数器减为0的时候所有因调用await方法而被阻塞的线程将被唤醒

11.乐观锁和悲观锁

乐观锁实现:版本号机制,CAS

乐观锁缺点:

1.ABA

2.循环时间长开销大

3.只能保证一个共享变量的原子操作

12.原子操作类

1.AtomicInteger:CAS+volatile修饰值保证可见性

2.AtomicReference(原子更新引用类型):CAS,解决了单个变量的原子操作问题

3.AtomicStampedReference(原子更新字段类):维护了一个对象值和版本号,解决了ABA问题

这篇关于对象面试官系列之Java并发--面试官看了都说好的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/489421

相关文章

Java Predicate接口定义详解

《JavaPredicate接口定义详解》Predicate是Java中的一个函数式接口,它代表一个判断逻辑,接收一个输入参数,返回一个布尔值,:本文主要介绍JavaPredicate接口的定义... 目录Java Predicate接口Java lamda表达式 Predicate<T>、BiFuncti

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Spring Security方法级安全控制@PreAuthorize注解的灵活运用小结

《SpringSecurity方法级安全控制@PreAuthorize注解的灵活运用小结》本文将带着大家讲解@PreAuthorize注解的核心原理、SpEL表达式机制,并通过的示例代码演示如... 目录1. 前言2. @PreAuthorize 注解简介3. @PreAuthorize 核心原理解析拦截与

一文详解JavaScript中的fetch方法

《一文详解JavaScript中的fetch方法》fetch函数是一个用于在JavaScript中执行HTTP请求的现代API,它提供了一种更简洁、更强大的方式来处理网络请求,:本文主要介绍Jav... 目录前言什么是 fetch 方法基本语法简单的 GET 请求示例代码解释发送 POST 请求示例代码解释

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

Java利用docx4j+Freemarker生成word文档

《Java利用docx4j+Freemarker生成word文档》这篇文章主要为大家详细介绍了Java如何利用docx4j+Freemarker生成word文档,文中的示例代码讲解详细,感兴趣的小伙伴... 目录技术方案maven依赖创建模板文件实现代码技术方案Java 1.8 + docx4j + Fr

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

基于SpringBoot+Mybatis实现Mysql分表

《基于SpringBoot+Mybatis实现Mysql分表》这篇文章主要为大家详细介绍了基于SpringBoot+Mybatis实现Mysql分表的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录基本思路定义注解创建ThreadLocal创建拦截器业务处理基本思路1.根据创建时间字段按年进