【两万字面试系列】三年前的面试题。Service里面的线程安全问题

前言

三年前,大概是21年,那会刚学完java,然后去面试,被打的一塌糊涂,今天来盘一盘之前的面试,到底是怎样的问题整住了。然后发现了去年整的线程安全东西,也贴到文章后面了。那个贴的还不太准,慢慢完善!会整完然后发B站视频。
在这里插入图片描述

线程安全

其实简单的来看就是线程安全的问题。现在来看这些问题好像没有什么,就是比较正常的问题。但是当时掌握的确实太不好了,然后可能面试官看我太菜了,这些回答不上来就没有接着往后续问了。大家看到这个面试题会想到什么呢,会想怎么回答和解决呢。
也可以结合一个实际的项目区演示和测试一番。写一个数字的成员变逻辑写计算然后看结果。

在Spring Boot中,处理Service层的线程安全问题是非常重要的,因为Spring的Service默认是单例的,这意味着Spring容器中只会创建一个Service实例。如果Service中包含了状态(即成员变量),那么在并发环境下可能会出现线程安全问题。以下是一些处理Service层线程安全问题的建议:

  1. 避免在Service中定义有状态的成员变量

尽量不要在Service中定义有状态的成员变量。如果确实需要存储状态,考虑将这些状态存储在方法内部的局部变量中,因为局部变量是线程安全的,它们存储在每个线程自己的栈中。
2. 使用线程安全的类

如果Service需要维护跨方法调用的状态,应该使用线程安全的类或数据结构,如ConcurrentHashMap、AtomicInteger等。
3. 同步访问共享资源(使用锁机制)

当多个线程需要访问同一个资源时,可以通过同步机制来保证线程安全。可以使用synchronized关键字或java.util.concurrent.locks包中的锁机制。但是,过度同步可能会导致性能问题,因此需要谨慎使用。
4. 使用ThreadLocal

ThreadLocal可以为每个线程提供一个变量的副本,使每个线程都有自己独立的变量副本,从而避免线程安全问题。但是,使用ThreadLocal时需要注意及时清理,避免内存泄漏。

  1. 使用@Scope注解(不建议)

如果确实需要Service有状态,可以考虑使用Spring的@Scope注解来改变Bean的作用域。例如,使用@Scope(“prototype”)注解可以让Spring容器为每个请求创建一个新的Service实例,这样可以避免多个请求共享同一个Service实例的线程安全问题。但这种方式会增加对象的创建和销毁的开销。

线程安全

在这里插入图片描述

后面是自己写的,还不是很完善,会补充的完善,然后B站发视频

3.线程方面

3.1线程安全
3.1. spring如何处理线程并发问题

spring的对象是默认是单例的。如果在里面声明成员变量的话。然后一个请求创建一个线程,多个线程同时请求一个资源就会出现问题。(单例bean是线程安全的)

解决方式有两种

1.将spring声明成多例

2.使用threadloacal

3.在代码块中加入同步锁 让他编程同步的 就可以解决了

相当于把并行编程了串行,会影响服务器他吞吐量。

4.成员变量声明在方法里面

3.2 tomcat线程模型

tomcat也已经支持异步了;但是他的效率比netty这种肯定还是要低的。

BIO :tomcat6默认采用的。每个请求都要创建一个线程来处理,线程开销较大,不能处理高并发

3.4 Volatile

涉及到可见性 ,禁止重排序

volatile与cas 通过乐观锁的思想来共同完成相应的reenTrankllock,具体在锁那块3.4里面有

3.5 Servlet

单实例 ,多线程

3.6 ThreadLocal

以空间换时间,给每个线程分配一个空间

ThreadLocal 是Java里一种特殊的变量。每个线程都有一个 ThreadLocal 就是每个线程都拥有了自己独立的一个变量,竞争条件被彻底消除了。如果为每个线程提供一个自己独有的变量拷贝,将大大提高效率。首先,通过复用减少了代价高昂的对象的创建个数。其次,你在没有使用高代价的同步或者不变性的情况下获得了线程安全。

3.7 ThreadLocal可能引发内存泄漏问题

1、强引用(StrongReference)
最普遍的一种引用方式,如String s = “abc”,变量s就是字符串“abc”的强引用,只要强引用存在,则垃圾回收器就不会回收这个对象。
2、软引用(SoftReference)
用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用于实现内存敏感的高速缓存,软引用可以和引用队列ReferenceQueue联合使用,如果软引用的对象被垃圾回收,JVM就会把这个软引用加入到与之关联的引用队列中。
3、弱引用(WeakReference)
弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。当一个对象既有弱引用又有强引用的时候不会清楚弱引用。短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。
ThreadLocal采用的是弱引用的key,当没有强引用来使用Thread Local的key时,key就会被回收。当我把ThreadLocal比作一个水桶,水桶上面有一个桶盖,我们在寻找桶的时候通过桶盖来寻找,但是当没有人惦记桶的时候,桶盖会自己丢失,这样我们没办法找到桶,也没法使用桶里的东西,这样就会导致内存泄漏。

 static class ThreadLocalMap {

        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
 }
	TreadLocalMap的Entry继承了WeakReference<ThreadLocal<?>>,即Entry的key是弱引用(该引用只存在弱引用的情况下,下一次GC]

ThreadLocal在保存的时候会把自己当做Key存在ThreadLocalMap中,正常情况应该是key和value都应该被外界强引用才对,但是现在key被设计成WeakReference弱引用了。

ThreadLocal的 key若引用 容易被GC回收,然后变成null。导入里面的 值没法被访问到,容易产生内存泄漏

3、解决方法

想象情况:如果一个线程被回收了,然后线程里面的成员变量也被回收,就没有内存泄漏的问题了。

实际情况:一般使用线程池,线程池是重复利用的,会存在内存泄漏的问题。ThreadLocal在进行数据读写的时候默认会进行一些清理的操作,找到并清理Entry里面key 为null 的数据

这个没有太好的解决方案,只能通过规范代码使用来解决最好是每次使用完ThreadLocal后,主动调用remove 方法去移除数据,把ThreadLocal 声明成全局变量,使他无法被GC回收

所以为了避免内存泄漏,在ThreadLocal使用结束以后,规范操作,执行下remove方法。

或者你可以从ThreadLocal,引出底层的Weak引用话题,再引出JVM结构以及OOM调优方面的话题。*

3.2 main方法线程(jvm创建线程过程)

一个程序创建一个jvm实例,一个进程,然后开辟一个线程

img

程序运行

JVM 在启动的时候会创建一个 VM Thread,这是所有线程的祖先,其他的线程都是由这个线程派生出去的。

在 Java 中,线程分为两种:普通线程守护线程

普通线程就是通常业务逻辑执行的代码,代码执行完成之后,普通线程也就退出了。而守护线程一般运行在后台,比如说响应命令行的操作,守护线程会在普通线程退出之后退出。

当程序执行完成之后,JVM 也要退出,程序执行完的标志就是非守护线程都退出了。当所有的非守护线程退出之后,守护线程也会退出。

程序在执行完成之后,会调用 System.exit() 方法,然后虚拟机退出,程序彻底结束。

exit 方法接收一个整型的参数,如果传入的值为 0,那么就表示程序是正常退出的,如果是任何非零的值,那么就表示是异常退出。

其实在代码中,非常不推荐调用这个方法,因为这个方法会造成一些意向不到的情况。

作者:Rayjun
链接:https://juejin.cn/post/6866744930376220679
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

3.3线程池

线程池的几个参数

包括阻塞队列这种

3.3.1线程池几大参数
3.3.1队列

无界队列oom

3.4锁

同步块大家都比较熟悉,通过 synchronized 关键字来实现;所有加上 synchronized 的方法和块语句,在多线程访问的时候,同一时刻只能有一个线程能够访问。

ConcurrentHashMap的锁

jdk1.8 使用到了 CAS+Volatile

synchronized+volatile(1.8版本)

CAS+Volatile

心想,确实是可以实现的呀!因为 AbstractQueuedSynchronizer(简称 AQS)内部就是通过 CAS + volatile(修饰同步标志位state) 实现的同步代码块。

volatile 保证了可见性和有序性,

cas 保证了原子性,像i++是三个操作,普通的保证不了这三个操作一起执行,然后使用cas 保证原子性。优点是可以保障原子性,但是缺点是有时候自旋时间太长,也会有问题。

AQS

AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock。 简单来说,AQS定义了一套框架,来实现同步类

AQS的核心思想是对于共享资源,维护一个双端队列来管理线程,队列中的线程依次获取资源,获取不到的线程进入队列等待,直到资源释放,队列中的线程依次获取资源。 AQS的基本框架如图所示:

AQS定义了一个实现同步类的框架,实现方法主要有tryAquiretryRelease,表示独占模式的资源获取和释放,tryAquireSharedtryReleaseShared表示共享模式的资源获取和释放。 源码分析如上文所述。

ReenTrankLock 锁
synchronized 锁对象头
Mysql的锁

表锁 行锁

CAS加volitale实现同步代码块,然后应用有 AQS ,

3.5 多线程 生产者与消费者

生产者 - 消费者模型 Producer-consumer problem 是一个非常经典的多线程并发协作的模型,在分布式系统里非常常见。

public void run() {
        synchronized (queue) {
            while (queue.size() == maxCapacity) { //一定要用 while,而不是 if,下文解释
                try {
                    System.out.println("生产者" + Thread.currentThread().getName() + "等待中... Queue 已达到最大容量,无法生产");
                    wait();
                    System.out.println("生产者" + Thread.currentThread().getName() + "退出等待");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (queue.size() == 0) { //队列里的产品从无到有,需要通知在等待的消费者
                queue.notifyAll();
            }
            Random random = new Random();
            Integer i = random.nextInt();
            queue.offer(new Product("产品"  + i.toString()));
            System.out.println("生产者" + Thread.currentThread().getName() + "生产了产品:" + i.toString());
        }
    }

作者:小齐本齐
链接:https://juejin.cn/post/6872131047032553486
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/420113.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024腾讯云服务器优惠价格表又降价了,给同行干emo了

腾讯云优惠活动2024新春采购节活动上线&#xff0c;云服务器价格已经出来了&#xff0c;云服务器61元一年起&#xff0c;配置和价格基本上和上个月没什么变化&#xff0c;但是新增了8888元代金券和会员续费优惠&#xff0c;腾讯云百科txybk.com整理腾讯云最新优惠活动云服务器配…

探索数据结构:解锁计算世界的密码

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 贝蒂的主页&#xff1a;Betty‘s blog 前言 随着应用程序变得越来越复杂和数据越来越丰富&#xff0c;几百万、…

每日五道java面试题之spring篇(九)

目录&#xff1a; 第一题. 说一下Spring的事务传播行为第二题. 说一下 spring 的事务隔离&#xff1f;第三题. Spring AOP and AspectJ AOP 有什么区别&#xff1f;AOP 有哪些实现方式&#xff1f;第四题. JDK动态代理和CGLIB动态代理的区别第五题. 解释一下Spring AOP里面的几…

基于SSM医院电子病历管理系统的设计与实现(源代码+数据库脚本+万字文档+PPT)

系统介绍 医院电子病历管理系统主要是借助计算机&#xff0c;通过对医院电子病历管理系统所需的信息管理&#xff0c;增加用户的选择&#xff0c;同时也方便对广大用户信息的及时查询、修改以及对用户信息的及时了解。医院电子病历管理系统 对用户带来了更多的便利&#xff0c…

1、jQuery介绍、css()、选择器、事件、动画

一、jQuery介绍&#xff1f; 1、什么是jQuery&#xff1f; 是一个JavaScript函数库 2、jQuery特点 写的少&#xff0c;做的多 3、jQuery的安装 直接下载引入 <script src"jquery-1.10.2.min.js"></script>通过cdn引入 <script src"https…

VScode 单步断点调试Nodejs方法总结

目录 方法一 方法二 方法三 方法一 使用vscode开发nodejs程序,能够启动单步调试模式,在指定代码处添加断点,像chrome、firefox浏览器上一样进行JavaScript的调试。 新建一个nodejs的工程,编写代码后,配置代码调试的步骤: 1、切换到代码调试界面 2、界面提示,新建一…

Python列表中添加删除元素不走弯路

1.append() 向列表中添加单个元素&#xff0c;一般用于尾部追加 list1 ["香妃", "乾隆", "贾南风", "赵飞燕", "汉武帝"]list1.append("周瑜") print(list1) # [香妃, 乾隆, 贾南风, 赵飞燕, 汉武帝, 周瑜]…

私域必备宝藏工具:多微信统一管理聚合聊天

对于私域流量运营者来说&#xff0c;如何高效管理多个微信号成为了一道难题。 不过不用担心&#xff0c;通过微信管理系统&#xff0c;可以实现多个微信同时登录&#xff0c;同一个界面内聚合聊天&#xff0c;省去来回切换账号的步骤。而且&#xff0c;还有很多非常实用且便捷…

幻兽帕鲁/Palworld服务器的最佳网络设置、内存和CPU配置是什么?

幻兽帕鲁/Palworld服务器的最佳网络设置、内存和CPU配置是什么&#xff1f; 对于4到8人的玩家&#xff0c;推荐的配置是4核16G的CPU和16G的内存。10到20人的玩家选择8核32G的CPU和32G或以上的内存。2到4人的玩家则建议选择4核8G的CPU和8G的内存。对于32人的玩家&#xff0c;推…

java常用环境docker安装

配置目录 rocketmqredismysql不配置binlog配置binlog Nacoszookeeper 本文为精简安装&#xff0c;部分不带容器卷映射&#xff0c;仅供以学习使用。 rocketmq nameservice sudo docker run -d \ --privilegedtrue \ --name rmqnamesrv \ -p 9876:9876 \ -e "MAX_HEAP_SI…

数据结构之二叉树的精讲

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

用按位或、按位与取反实现权限的增减

一、介绍&#xff1a; 在Linux操作系统中&#xff1a; r -4&#xff1a;可读权限 w -2&#xff1a;可写权限 x -1&#xff1a;可执行权限 问题1&#xff1a;三个权限为1,2,4&#xff0c;分别对应:2^0,2^1,2^2&#xff0c;为什么要用8进制表示用户的文件权限&#xff1f; …

《汇编语言》第3版 (王爽)检测点3.1解析

第三章 检测点3.1 &#xff08;1&#xff09;.在Debug中&#xff0c;用“d 0:0 1f”查看内存&#xff0c;结果如下。 下面的程序执行前&#xff0c;AX 0&#xff0c;BX 0&#xff0c;写出每条汇编指令执行完后相关寄存器中的值。 mov ax,1 ;将1放入AX寄存器中&#xff0c;…

奥威BI+用友,分析呆滞物料库存

对库存安全来说&#xff0c;呆滞物料就是一个不定时危机&#xff0c;需要时刻监控呆滞物料库存&#xff0c;既要保证满足生产所需&#xff0c;又要避免库存量过大给库存造成负担以及物料贬值造成损失。那&#xff0c;呆滞物料库存怎么分析&#xff1f;奥威-用友BI方案做了一个样…

使用css的transition属性实现抽屉功能

需求 使用css手写一个抽屉&#xff0c;并且不能遮挡住原来的页面 效果&#xff1a;&#xff08;录的gif有点卡&#xff0c;实际情况很丝滑&#xff09; 实现代码&#xff1a; <template><div class"dashboard-container"><div class"mainBox&…

android移动应用开发教程,android系统工程师面试宝典

Java相关 Java基础 HashMap1.7和1.8的实现原理final关键字&#xff0c;为什么匿名内部类使用局部引用要用final Java多线程 线程池的使用和原理 锁机制&#xff1a;synchronized、Lock volatile关键字 ThreadLocal原理 JVM Java内存结构Java垃圾回收机制Java类加载过程…

基于CVX凸优化的电动汽车充放电调度matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 CVX凸优化 4.2 电动汽车充放电调度 5.完整程序 1.程序功能描述 基于CVX凸优化的电动汽车充放电调度.仿真输出无电动汽车充电时的负载&#xff0c;电动汽车充电时cvx全局优化求解后的总…

牛客周赛 Round 34(A,B,C,D,E,F,G)

把这场忘了。。官方也迟迟不发题解 比赛链接 出题人题解 A 小红的字符串生成 思路&#xff1a; 枚举四种字符串打印出来即可&#xff0c;为了防止重复可以用set先去一下重。 code&#xff1a; #include <iostream> #include <cstdio> #include <cstring&g…

kubernetes最新版安装单机版v1.21.5

k8s集群由Master节点和Node&#xff08;Worker&#xff09;节点组成。 1.环境 环境&#xff1a;centos 7资源配置&#xff1a;2c4g &#xff08;CPU最少2c&#xff0c;不然k8s起不来&#xff09;docker&#xff1a;25.0.3k8s&#xff1a;1.21.5 2.安装前置环境 [rootbertra…

代码随想录算法刷题训练营day28:LeetCode(93)复原IP地址 、LeetCode(78)子集 、LeetCode(90)子集II

代码随想录算法刷题训练营day28&#xff1a;LeetCode(93)复原IP地址 、LeetCode(78)子集 、LeetCode(90)子集II LeetCode(93)复原IP地址 题目 代码 import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List;class Solu…