美团java一面面经

news/2024/5/19 15:44:23/文章来源:https://blog.csdn.net/qq_46548855/article/details/127014286

目录

  • 1.了解static吗,static数据存在哪?生命周期什么样的
  • 2.了解final吗,讲讲下面这段代码的结果
  • 3.讲讲volatile吧
  • 4.讲讲两个锁的区别(reentrantlock和synchronized)
  • 5.讲讲线程池里线程的创建与销毁,核心线程可以销毁吗?
  • 6.高并发怎么减少锁的竞争
  • 7.了解类加载机制吗,讲讲下面这段代码运行结果
  • 8.hashMap为什么大小是幂次
  • 9.euqal和==的区别,equal没有重写的时候默认是什么
  • 10.写个sql吧,学号 学生姓名 科目 成绩 班级,选出每个班的每个科目最高分
  • 11.linux的tail -f命令里的f是什么意思
  • 12.用过grep吗,会正则吗
  • 13.mysql 事务的特性
  • 14.char和varchar的区别
  • 15.如果我一个字段是char(10),我只存三个字节进去,它底层文件占几个字节
  • 16.计算机网络:TCP如何保证数据包不丢、不重、不乱、完整性
  • 17.arraylist调api找里面值为10的下标
  • 18.自动拆箱装箱了解吗

1.了解static吗,static数据存在哪?生命周期什么样的

存放: 静态变量存放在方法区中,并且是被所有线程所共享的
生命周期: 静态变量随着类的加载而加载,也意味着随着类的消失而消失
类的加载经历了5个过程(装载,链接,初始化,使用,卸载)

2.了解final吗,讲讲下面这段代码的结果

String s = "hello2";
final String s2 = "hello";
String s3 = s2+2;
System.out.println(s==s3);

true
常量和常量相加还是常量,并且在串池中,final关键字修饰后则会在编译期就解析为一个常量值放到常量池中
拓展

String s = "hello2";
String s1 = "hello";
String s2 = "2"
String s3 = s1 + s2;
System.out.println(s==s3);

在栈中存在s,s指向字符串常量池中的hello2
在栈中存在s1,s1指向字符串常量池中的hello
在栈中存在s2,s2指向字符串常量池中的2
在栈中存放s3,而s1+s2则会通过StringBuilder中的toString()方法在堆中创建一个hello2
这时就可以看出来s指向字符串常量池中的hello2,而s3则指向堆中的hello2

3.讲讲volatile吧

1.volatile是什么?
volatile是一个轻量级的synchronized,一般作用于变量,在多处理器开发的过程中保证了内存的可见性。相比于synchronized关键字,volatile关键字的执行成本更低,效率更高。
2.volatile的特性有哪些?
可见性,有序性(从这两个点依次去答)
3.java内存中可见性的问题
JMM(Java内存模型Java Memory Model,简称JMM)本身是一种抽象的概念并不真实存在
在这里插入图片描述
代码展示

public class VolatileSeeDemo {//static boolean flag = true;       //不加volatile,没有可见性static volatile boolean flag = true;       //加了volatile,保证可见性public static void main(String[] args) {new Thread(() -> {System.out.println(Thread.currentThread().getName() + "\t come in");while (flag) {}System.out.println(Thread.currentThread().getName() + "\t flag被修改为false,退出.....");}, "t1").start();//暂停2秒钟后让main线程修改flag值try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}flag = false;System.out.println("main线程修改完成");}
}

问题可能:

  1. 主线程修改了flag之后没有将其刷新到主内存,所以t1线程看不到。
  2. 主线程将flag刷新到了主内存,但是t1一直读取的是自己工作内存中flag的值,没有去主内存中更新获取flag最新的值。

我们的诉求:

  1. 线程中修改了工作内存中的副本之后,立即将其刷新到主内存;
  2. 工作内存中每次读取共享变量时,都去主内存中重新读取,然后拷贝到工作内存。

解决:
使用volatile修饰共享变量,就可以达到上面的效果,被volatile修改的变量有以下特点:

  1. 线程中读取的时候,每次读取都会去主内存中读取共享变量最新的值,然后将其复制到工作内存
  2. 线程中修改了工作内存中变量的副本,修改之后会立即刷新到主内存

4.volatile为啥不具有原子性
volatile变量的复合操作(如i++)不具有原子性
在这里插入图片描述
原子性指的是一个操作是不可中断的,即使是在多线程环境下,一个操作一旦开始就不会被其他线程影响。
volatile变量的读写过程
read(读取)→load(加载)→use(使用)→assign(赋值)→store(存储)→write(写入)→lock(锁定)→unlock(解锁)

read: 作用于主内存,将变量的值从主内存传输到工作内存,主内存到工作内存
load: 作用于工作内存,将read从主内存传输的变量值放入工作内存变量副本中,即数据加载
use: 作用于工作内存,将工作内存变量副本的值传递给执行引擎,每当JVM遇到需要该变量的字节码指令时会执行该操作
assign: 作用于工作内存,将从执行引擎接收到的值赋值给工作内存变量,每当JVM遇到一个给变量赋值字节码指令时会执行该操作
store: 作用于工作内存,将赋值完毕的工作变量的值写回给主内存
write: 作用于主内存,将store传输过来的变量值赋值给主内存中的变量
由于上述只能保证单条指令的原子性,针对多条指令的组合性原子保证,没有大面积加锁,所以,JVM提供了另外两个原子指令:
lock: 作用于主内存,将一个变量标记为一个线程独占的状态,只是写时候加锁,就只是锁了写变量的过程。
unlock: 作用于主内存,把一个处于锁定状态的变量释放,然后才能被其他线程占用
在这里插入图片描述
5.指令禁重排
重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段,有时候会改变程序语句的先后顺序
不存在数据依赖关系,可以重排序;
存在数据依赖关系,禁止重排序;
在这里插入图片描述
编译器优化的重排序: 编译器在不改变单线程串行语义的前提下,可以重新调整指令的执行顺序
指令级并行的重排序: 处理器使用指令级并行技术来讲多条指令重叠执行,若不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序
内存系统的重排序: 由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是乱序执行
案例 :
不存在数据依赖关系,可以重排序===> 重排序OK 。
在这里插入图片描述
存在数据依赖关系,禁止重排序===> 重排序发生,会导致程序运行结果不同。
在这里插入图片描述
6.重排序会引发什么问题?
在单线程程序中,重排序并不会影响程序的运行结果,而在多线程场景下就不一定了。

class ReorderExample{int a = 0;boolean flag = false;public void writer(){a = 1;              // 操作1flag = true;        // 操作2}public void reader(){if(flag){          // 操作3int i = a + a; // 操作4}}
}

假设线程1先执行writer()方法,随后线程2执行reader()方法,最后程序一定会得到正确的结果吗?
答案是不一定的,如果代码按照下图的执行顺序执行代码则会出现问题。
在这里插入图片描述
操作1和操作2进行了重排序,线程1先执行flag=true,然后线程2执行操作3和操作4,线程2执行操作4时不能正确读取到a的值,导致最终程序运行结果出问题。这也说明了在多线程代码中,重排序会破坏多线程程序的语义。
7.happens-before规则的区别?
在这里插入图片描述
1.当第一个操作为volatile读时,不论第二个操作是什么,都不能重排序。这个操作保证了volatile读之后的操作不会被重排到volatile读之前。
2.当第二个操作为volatile写时,不论第一个操作是什么,都不能重排序。这个操作保证了volatile写之前的操作不会被重排到volatile写之后。
3.当第一个操作为volatile写时,第二个操作为volatile读时,不能重排。
8.Java虚拟机插入内存屏障的策略
读屏障

  1. 在每个 volatile 读操作的后⾯插⼊⼀个 LoadLoad 屏障
  2. 在每个 volatile 读操作的后⾯插⼊⼀个 LoadStore 屏障
    在这里插入图片描述

写屏障

  1. 在每个 volatile 写操作的前⾯插⼊⼀个 StoreStore 屏障
  2. 在每个 volatile 写操作的后⾯插⼊⼀个 StoreLoad 屏障

加StoreStore位是为保证所有普通写操作都已经刷新到主内存了
在这里插入图片描述
在这里插入图片描述
总结
在这里插入图片描述

4.讲讲两个锁的区别(reentrantlock和synchronized)

底层实现

  • synchronized是JVM层面的锁,也是Java的关键字,通过monitor对象进行完成的。ReentrantLock是JDK提供的API层面的锁

是否需要手动释放

  • synchronized不需要用户去手动释放锁,ReentrantLock则需要用户去手动释放锁(lock和unlock)。

是否可中断

  • synchronized是不可中断类型的锁,ReentrantLock是可以中断的

是否可以绑定多个条件

  • ReentrantLock可以同时绑定多个Condition对象,只需多次调用newCondition方法即可。
  • synchronized中,锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含的条件。但如果要和多于一个的条件关联的时候,就不得不额外添加一个锁。

公平锁

  • synchronized的锁是非公平锁,ReentrantLock默认情况下也是非公平锁,但可以通过带布尔值的构造函数要求使用公平锁。

5.讲讲线程池里线程的创建与销毁,核心线程可以销毁吗?

线程池的创建:
线程池的常用创建方式主要有两种,通过Executors工厂方法创建和通过new ThreadPoolExecutor方法创建。
Executors工厂方法创建,在工具类 Executors 提供了一些静态的工厂方法

  • newSingleThreadExecutor:创建一个单线程的线程池。
  • newFixedThreadPool:创建固定大小的线程池。
  • newCachedThreadPool:创建一个可缓存的线程池。
  • newScheduledThreadPool:创建一个大小无限的线程池。

new ThreadPoolExecutor 方法创建:

  • 通过newThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)自定义创建

线程池的关闭:
线程池的关闭可以调用线程池中的shutdown或shutdownNow方法进行关闭,它们会遍历线程池中的工作线程,然后调用每个线程的interrupt方法来中断线程。

核心线程可以销毁吗?
在 runWorker 方法中,首先会去执行创建这个 worker 时就有的任务,当执行完这个任务之后, worker 并不会被销毁,而是在 while 循环中, worker 会不断的调用 getTask 方法从阻塞队列中获取任务然后调用 task。run() 来执行任务,这样就达到了复用线程的目的。通过循环条件 while (task != null || (task = getTask()) != null) 可以看出,只要 getTask 方法返回值不为 null ,就会一直循环下去,这个线程也就会一直在执行,从而达到了线程复用的目的
在这里插入图片描述
task!=null可能是false
在这里插入图片描述
getTask()为啥会一直不为null
allowCoreThreadTimeOut默认为false
allowCoreThreadTimeOut为true该值为true,则线程池数量最后销毁到0个。
那么timed为false

boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

接下来我们会走take方法
poll:移除方法,成功返回出队列的元素,队列里没有就返回null
take:当阻塞队列空时,消费者线程试图从队列里take元素,队列会一直阻塞消费者线程直到队列可用
在这里插入图片描述

6.高并发怎么减少锁的竞争

减少锁的持有时间。
减少锁粒度。
锁分离。
锁粗化。
锁消除。

7.了解类加载机制吗,讲讲下面这段代码运行结果

class Father {private String a = "father";public Father() {say();}public void say() {System.out.println("i'm father" + a);}
}
class Sub extends Father {private String a = "child";@Overridepublic void say() {System.out.println("i'm child" + a);}
}
public class Test {public static void main(String[] args) {Father father = new Father();Sub sub = new Sub();}
}

类的加载机制:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

i'm fatherfather
i'm childnull

大家可以先记住代码执行顺序:
静态代码块(父) > 静态代码块(子) > 实例成员变量(父) > 构造代码块(父) > 构造方法(父) > 实例成员变量(子) > 构造代码块(子) > 构造方法(子)

Father father = new Father();—>private String a = “father”;—>public Father( { say() ;}—>执行say()方法,结果为i’m fatherfather

Sub sub = new Sub();—>private String a = “father”;—>public Father( { say() ;}—>调用子类的say()方法,因为子类的实例成员变量并未初始化,所以结果为i’m childnull

8.hashMap为什么大小是幂次

为了加快哈希计算以及减少哈希冲突
index = HashCode(Key) & (Length - 1)
下面我们以“book”的Key来演示整个过程:
1.计算book的hashcode,结果为十进制的3029737,二进制的101110001110101110 1001。
2.假定HashMap长度是默认的16,计算Length-1的结果为十进制的15,二进制的1111。
3.把以上两个结果做与运算,101110001110101110 1001 & 1111 = 1001,十进制是9,所以 index=9。
可以说,Hash算法最终得到的index结果,完全取决于Key的Hashcode值的最后几位。

9.euqal和==的区别,equal没有重写的时候默认是什么

==
对于基本数据类型, == 比较的是值;对于引用数据类型,== 比较的是内存地址。
eauals
对于没有重写equals方法的类,equals方法和== 作用类似;对于重写过equals方法的类,equals比较的是值。
如果没有重写equal(),那么equals和 == 的作用相同,比较的是对象的地址值。

基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress,
引用类型包括:类类型,接口类型和数组。

10.写个sql吧,学号 学生姓名 科目 成绩 班级,选出每个班的每个科目最高分

select max(成绩) from 表名 group by 班级,科目

11.linux的tail -f命令里的f是什么意思

tail(尾巴的意思),用来查看文件最后几行的数据,默认是10行
tail -f filename 会把 filename 文件里的最尾部的内容显示在屏幕上,并且不断刷新,只要 filename 更新就可以看到最新的文件内容。

12.用过grep吗,会正则吗

grep是一个文本过滤器,作用是在文件中查找符合我们要求的内容。

13.mysql 事务的特性

原子性:原子性是指包含事务的操作要么全部执行成功,要么全部失败回滚。
一致性:一致性指事务在执行前后状态是一致的。
隔离性:一个事务所进行的修改在最终提交之前,对其他事务是不可见的。
持久性:数据一旦提交,其所作的修改将永久地保存到数据库中。

14.char和varchar的区别

字符串常用的主要有CHAR和VARCHAR,VARCHAR主要用于存储可变长字符串,相比于定长的CHAR更节省空间。CHAR是定长的,根据定义的字符串长度分配空间。
在这里插入图片描述

15.如果我一个字段是char(10),我只存三个字节进去,它底层文件占几个字节

10个,剩余七个会用空格填充。

16.计算机网络:TCP如何保证数据包不丢、不重、不乱、完整性

后续更新

17.arraylist调api找里面值为10的下标

indexOf

18.自动拆箱装箱了解吗

装箱:将基本类型用包装器类型包装起来
拆箱:将包装器类型转换为基本类型

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

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

相关文章

.NET 开源项目推荐之 直播控制台解决方案 Macro Deck

在直播圈有个很受欢迎的直播控制台程序Macro Deck, 它是基于Apache 2.0协议开源的.NET 应用。流媒体是一个吸引数亿万玩家的严肃行业。 最受欢迎的游戏锦标赛的转播获得了数百万的观看次数,从商业角度来看,这也使游戏行业变得有趣。在直播圈有个很受欢迎的直播控制台程序Mac…

牛客网专项练习30天Pytnon篇第07天

1.在Python中,使用open方法打开文件,语法如下:open(文件名,访问模式),如果以二进制格式打开一个文件用于追加,则访问模式为:(C) A.rb B.wb C.ab D.a 解析: "r",&q…

看完这篇 教你玩转渗透测试靶机vulnhub——hackableII

Vulnhub靶机hackableII渗透测试详解Vulnhub靶机介绍:Vulnhub靶机下载:Vulnhub靶机安装:Vulnhub靶机漏洞详解:①:信息收集:②:FTP匿名登录:③:回弹shell:④&am…

Mybatis - 一二级缓存的原理

Mybatis - 一二级缓存的原理前言一. 一级缓存原理1.1 原理分析1.2 一级缓存 Key1.3 查询逻辑1.4 一级缓存的清除或失效场景1.5 一级缓存总结二. 二级缓存原理2.1 二级缓存的实验2.2 二级缓存的开启和相关配置解析2.3 二级缓存的封装Cache类2.4 二级缓存的存储2.5 二级缓存总结前…

指静脉代码学习---9.图像质量评价(分类)

一、论文背景 1.论文三--Song 本文提出了一种自适应增强框架的算法流程 先通过质量评价将图像分类,①针对高质量的图像,采用类似直方图均衡化的简单方法②低质量图像,采用类似滤波器增强的方法(虽然时效性较差,但是效果比较明显) ①对质量评价方法历程的概述:

Python 变量作用域

Python 变量作用域1.变量作用域2.局部变量3.全局变量4.同名的局部变量和全局变量5.global 语句1.变量作用域 Python 中规定每个变量都有它的作用域, 即变量只有在作用域范围内才是可见可用的。 作用域能避免程序代码中的名称冲突,在一个函数中定义的变量…

Java学习 --- 面向对象-继承

一、为什么需要继承 我们编写了两个类,一个是Pupil类,一个是Graduate类 问题:两个类的属性和方法有很多是相同的,怎么办? Pupil类: package com.javase.extend_;public class Pupil {public String nam…

docker搭建2048小游戏

下载2048游戏包 链接: https://pan.baidu.com/s/1E5RkGgfLSo3XYmvJ7RId_Q 提取码: 1gc5 复制这段内容后打开百度网盘手机App,操作更方便哦 打包成镜像 [root@docker ~]# ls game2048.tar [root@docker ~]# docker load -i game2048.tar [root@docker ~]# docker images REPOSI…

10月7日第壹简报,星期五,农历九月十二

10月7日第壹简报,星期五,农历九月十二1. 2022年诺贝尔文学奖揭晓,82岁法国女作家埃尔诺获奖。2. 我国新添4处世界灌溉工程遗产:四川省通济堰、江苏省兴化垛田灌排工程体系、浙江省松阳松古灌区和江西省崇义县上堡梯田全部申报成功…

【C语言】学生考勤管理系统

✅作者简介:一位CSDN万粉博主的小娇妻,一名在读大二学生,希望大家多多支持👍👍👍 🔥系列专栏:C语言 💬个人主页:梦园的CSDN博客 学生考勤管理系统1 问题描述2…

使用Vue和SpringBoot开发实验室耗材智能运维系统

作者主页:Designer 小郑 作者简介:浙江某公司软件工程师,负责开发管理公司OA、CRM业务系统,全栈领域优质创作者,CSDN学院、蓝桥云课认证讲师,开发过20余个前后端分离实战项目,主要发展方向为Vue…

(附源码)计算机毕业设计ssm大学生社团管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

SPAFA 和Dijkstra的区别

Dijkstra算法和SPFA算法都可以用于求单源最短路,前者可以用小根堆进行优化,后者用就是用队列优化过的Bell-man Ford,下面说一说这两者的区别: Dijkstra算法是基于贪心和DP的思路,一开始先将所有点到原点的距离设置为无穷大,特别的是dis[s]=0,此处的s为原点,它是每次找到…

基于Java的SQL Server数据库加解密系统设计与实现

目 录 摘 要 1 ABSTRACT 2 第1章 绪论 3 1.1 数据库加解密系统开发背景 3 1.2 国内外现状 3 1.3 本文的主要工作 4 1.4 论文的组织结构 4 第2章 数据库加密的基本理论 6 2.1 数据库加密的三种级别 6 2.2 数据库加密的粒度 8 2.2.1 数据库级的数据库加密 8 2.2.2 表(…

(附源码)SSM药品销售平台设计与实现JAVA计算机毕业设计项目

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

python读写操作redis数据库

python读写操作redis数据库 redis有16个逻辑数据库(编号db0到db15),每个逻辑数据库数据是隔离的,默认db0。选择第n个逻辑数据库,命令select n ,python连接时可指定数据库编号(0~15)…

【Linux内核】内存管理——内核的内存分区

转载请注明: https://www.cnblogs.com/Ethan-Code/p/16619091.html 内核的内存分区 32位机中的虚拟内存大小为4GB,其中0~3GB用于用户空间,3~4GB用于内核空间。 内核的内存空间只有1G,这一部分内存在进程中共享,与用户空间隔离&…

WSL2和Docker使用GPU

文章目录安装Docker-Desktop简单配置dockerwin10安装支持WSL2的nvidia驱动ubuntu配置 CUDA ToolkitGPU测试及问题处理安装Docker-Desktop 安装Docker-Desktop Docker-Desktop下载地址 :https://www.docker.com/products/docker-desktop/ 接着就一路无脑安装即可。 下载完成之…

PTA - 数据库合集10

目录 10-52 查询姓‘李’的学生记录 10-54 查询所有学生的平均成绩 10-67 sql-insert-sample 10-68 sql-delete-sample 10-72 单表查询:根据运费查询订单信息 10-52 查询姓‘李’的学生记录 分数 5 全屏浏览题目 切换布局 作者 张庆 单位 集美大学 本题目要…

MaxViT实战:使用MaxViT实现图像分类任务(一)

MaxViT实战摘要安装包安装timm数据增强Cutout和MixupEMA项目结构计算mean和std生成数据集摘要 MaxViT,是今年谷歌提出分层Transformer的模型,将注意力模型与卷积有效地融合在一起。在图像分类方面,MaxViT 在各种设置下都达到了最先进的性能&…