【Java 高频面试闯关秘籍】大梦谁先觉,平生我自知

CentOS7上装不了最新Chrome?别折腾依赖了,试试这个老版本安装法(附103.0.5060.24 beta下载地址) 本文提供了在CentOS7上安装兼容版Chrome的详细指南,解决了因GLIBC版本限制导致的最新版Chrome无法安装的问题。推荐使用Chrome 103.0.5060.24 beta版本,并附有下载地址和完整安装步骤,包括禁用自动更新和配套工具安装,确保系统稳定性和功能完整性。 阅读详情

一、mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句?

关键点:

(1)如果排序字段不在索引列上,filesort有两种算法:mysql就要启动双路排序和单路排序
(2)无过滤不索引
(3)order by 非最左filesort
(4)顺序错 filesort
(5)方向反 filesort

答案:

(1)首先要对SQL进行分析检查必要的的查询字段、过滤字段、排序字段是否按顺序创建好了索引;
(2)如果查询字段不再索引中,可能会产生回表操作导致filesort降低性能;
(3)一定要过滤字段不然不能使用索引;
(4)排序字段和索引顺序不一致会导致filesort降低性能;
(5)多个字段排序时如果方向不一致也会导致filesort,降低性能;
(6)使用explain观察查询类型和索引利用情况;
(7)尽可能减少不必要的filesort;

实验准备:向表中插入50w条数据

在做优化之前,要准备大量数据。接下来创建两张表,并往员工表里插入50W数据,部门表中插入1W条数据。
怎么快速插入50w条数据呢? 存储过程
怎么保证插入的数据不重复?函数

部门表:

  • id:自增长

  • deptName:随机字符串,允许重复

  • address:随机字符串,允许重复

  • CEO:1-50w之间的任意数字

员工表:

  • id:自增长
  • empno:可以使用随机数字,或者从1开始的自增数字,不允许重复
  • name:随机生成,允许姓名重复
  • age:区间随机数
  • deptId:1-1w之间随机数

总结: 需要产生随机字符串和区间随机数的函数。

创建表

CREATE TABLE `dept` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`deptName` VARCHAR(30) DEFAULT NULL,
	`address` VARCHAR(40) DEFAULT NULL,
	ceo INT NULL ,
	PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1;

CREATE TABLE `emp` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`empno` INT NOT NULL ,
	`name` VARCHAR(20) DEFAULT NULL,
	`age` INT(3) DEFAULT NULL,
	`deptId` INT(11) DEFAULT NULL,
	PRIMARY KEY (`id`)
	#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1;

创建函数

-- 查看mysql是否允许创建函数:
SHOW VARIABLES LIKE 'log_bin_trust_function_creators';
-- 命令开启:允许创建函数设置:(global-所有session都生效)
SET GLOBAL log_bin_trust_function_creators=1; 
-- 随机产生字符串
DELIMITER $$
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
BEGIN    
	DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
	DECLARE return_str VARCHAR(255) DEFAULT '';
	DECLARE i INT DEFAULT 0;
	WHILE i < n DO  
		SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));  
		SET i = i + 1;
	END WHILE;
	RETURN return_str;
END $$

-- 假如要删除
-- drop function rand_string;
-- 用于随机产生区间数字
DELIMITER $$
CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11)
BEGIN   
 DECLARE i INT DEFAULT 0;  
 SET i = FLOOR(from_num +RAND()*(to_num -from_num+1));
RETURN i;  
END$$

-- 假如要删除
-- drop function rand_num;

创建存储过程

-- 插入员工数据
DELIMITER $$
CREATE PROCEDURE  insert_emp(START INT, max_num INT)
BEGIN  
	DECLARE i INT DEFAULT 0;   
	#set autocommit =0 把autocommit设置成0  
	SET autocommit = 0;    
	REPEAT  
		SET i = i + 1;  
		INSERT INTO emp (empno, NAME, age, deptid ) VALUES ((START+i) ,rand_string(6), rand_num(30,50), rand_num(1,10000));  
		UNTIL i = max_num  
	END REPEAT;  
	COMMIT;  
END$$
 
-- 删除
-- DELIMITER ;
-- drop PROCEDURE insert_emp;
-- 插入部门数据
DELIMITER $$
CREATE PROCEDURE insert_dept(max_num INT)
BEGIN  
	DECLARE i INT DEFAULT 0;   
	SET autocommit = 0;    
	REPEAT  
		SET i = i + 1;  
		INSERT INTO dept ( deptname,address,ceo ) VALUES (rand_string(8),rand_string(10),rand_num(1,500000));  
		UNTIL i = max_num  
	END REPEAT;  
	COMMIT;  
END$$
 
-- 删除
-- DELIMITER ;
-- drop PROCEDURE insert_dept;

调用存储过程

-- 执行存储过程,往dept表添加1万条数据
CALL insert_dept(10000); 

-- 执行存储过程,往emp表添加50万条数据,编号从100000开始
CALL insert_emp(100000,500000); 

批量删除表索引

-- 批量删除某个表上的所有索引
DELIMITER $$
CREATE PROCEDURE `proc_drop_index`(dbname VARCHAR(200),tablename VARCHAR(200))
BEGIN
	DECLARE done INT DEFAULT 0;
	DECLARE ct INT DEFAULT 0;
	DECLARE _index VARCHAR(200) DEFAULT '';
	DECLARE _cur CURSOR FOR SELECT index_name FROM information_schema.STATISTICS WHERE table_schema=dbname AND table_name=tablename AND seq_in_index=1 AND index_name <>'PRIMARY'  ;
	DECLARE CONTINUE HANDLER FOR NOT FOUND set done=2 ;      
	OPEN _cur;
		FETCH _cur INTO _index;
		WHILE  _index<>'' DO 
			SET @str = CONCAT("drop index ",_index," on ",tablename ); 
			PREPARE sql_str FROM @str ;
			EXECUTE sql_str;
			DEALLOCATE PREPARE sql_str;
			SET _index=''; 
			FETCH _cur INTO _index; 
		END WHILE;
	CLOSE _cur;
END$$
-- 执行批量删除:dbname 库名称, tablename 表名称
CALL proc_drop_index("dbname","tablename"); 

最左前缀法则示例

假设index(a,b,c)

Where语句索引是否被使用
where a = 3Y,使用到a
where a = 3 and b = 5Y,使用到a,b
where a = 3 and b = 5 and c = 4Y,使用到a,b,c
where b = 3 或者 where b = 3 and c = 4 或者 where c = 4N
where a = 3 and c = 5使用到a, 但是c不可以,b中间断了
where a = 3 and b > 4 and c = 5使用到a和b, c不能用在范围之后,b断了
where a is null and b is not nullis null 支持索引 但是is not null 不支持,所以 a 可以使用索引,但是 b不一定能用上索引(8.0)
where a <> 3不能使用索引
where abs(a) =3不能使用 索引
where a = 3 and b like ‘kk%’ and c = 4Y,使用到a,b,c
where a = 3 and b like ‘%kk’ and c = 4Y,只用到a
where a = 3 and b like ‘%kk%’ and c = 4Y,只用到a
where a = 3 and b like ‘k%kk%’ and c = 4Y,使用到a,b,c

一般性建议

Ø 对于单键索引,尽量选择过滤性更好的索引(例如:手机号,邮件,身份证)

Ø 在选择组合索引的时候,过滤性最好的字段在索引字段顺序中,位置越靠前越好。

Ø 选择组合索引时,尽量包含where中更多字段的索引

Ø 组合索引出现范围查询时,尽量把这个字段放在索引次序的最后面

Ø 尽量避免造成索引失效的情况

开始实验

删除索引: drop index idx_age_name_deptid on emp;
创建索引:CREATE INDEX idx_age_deptid_name ON emp (age,deptid,NAME);

1、无过滤不索引
EXPLAIN SELECT * FROM emp ORDER BY age,deptid; 
EXPLAIN SELECT * FROM emp ORDER BY age,deptid LIMIT 10; 

增加过滤条件,使用上索引了。
EXPLAIN SELECT age FROM emp where age>1000 ORDER BY age,deptid,name;
2、查询条件与筛选条件
const查询排序后回表操作,不会filesort
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY age,deptid,NAME; 

range查询,Using index condition 没有完全使用索引
EXPLAIN SELECT * FROM emp WHERE age>45 ORDER BY age,deptid,NAME;
range查询,Using where; Using index 完全使用索引
EXPLAIN SELECT age FROM emp WHERE age>45 ORDER BY age,deptid,NAME;
3、顺序错 filesort
正常情况
EXPLAIN SELECT age FROM emp WHERE age>45 ORDER BY age,deptid,NAME;
order by顺序变化会导致filesort
EXPLAIN SELECT age FROM emp WHERE age>45 ORDER BY deptid,age,NAME;
4、order by非最左 filesort
EXPLAIN SELECT age FROM emp WHERE age>45 ORDER BY deptid,NAME;
5、方向反 必排序
8.0为Backward index scan 倒序索引
EXPLAIN SELECT age FROM emp WHERE age>45 ORDER BY age desc,deptid desc,NAME desc

方向反 产生filesort
EXPLAIN SELECT age FROM emp WHERE age>45 ORDER BY age desc,deptid desc,NAME asc;

二、数据库索引的原理?创建索引的缺点是什么,什么情况索引失效?优化数据库的方法有哪些?

1、数据库索引的原理?

(1)以MySQL为例,默认引擎innoDB使用了b+树实现索引,在索引查找时,实现了log(n)的时间复杂度;
(2)聚簇索引记录了主键ID【完整数据】,非聚簇索引的索引树中记录数据【索引字段+主键】;
(3)在聚簇索引的叶子节点中记录了完整的值,非聚簇索引的叶子节点记录的是主键以及索引字段,如果需要完整值的话需要回表操作,即使用主键去聚簇索引中再次查找完整数据;
(4)索引的叶子节点以链表的形式存储,方便顺序查找和排序;

2、创建索引的缺点是什么?

(1)会占用空间;(2)更新时会级联更新索引;(3)高并发写影响性能;

3、什么情况索引失效?

(1)计算、函数导致索引失效;(2)LIKE以%开头索引失效;(3)不等于【!=】;(4)IS NOT NULL 可能失效【不同版本和数据决定】IS NULL 有效;(5)类型转换导致索引失效;(6)数据库优化器觉得不用索引更快的时候失效;

4、优化数据库的方法有哪些?

(1)硬件【主要在存储层优化】;(2)网络;(3)操作系统调优;(4)表结构设计优化;(5)sql优化;(6)减少函数使用;(7)索引优化;(8)大字段及全文检索优化;(9)连接池优化;(10)事务优化;(11)数据库集群化;(12)加入缓存;(13)冷热存储;(14)分库分表;

三、数据连接池的工作机制是什么?

答:
1. 预先创建好一些数据库连接,放到连接池中
2. 连接池中设置最小连接数和最大连接数
3. 最小连接不断开和数据库的连接
4. 超过最小链接的那些线程,在长时间不使用时会被回收,也就是断开和数据库的连接
5. 所有向数据库发送请求的业务必须通过连接池获得数据库连接
6. 当连接全部在使用中,可以使用队列等待

四、说一下MySQL中事务的实现原理

Multi-Version Concurrency Control 多版本并发控制,MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问

InnoDB是一个多版本的存储引擎。它保存有关已更改行的旧版本的信息,以支持并发和回滚等事务特性。这些信息存储在一个称为回滚段的数据结构中的系统表空间或undo表空间中。参见第14.6.3.4节“撤消表空间”。InnoDB使用回滚段中的信息来执行事务回滚所需的撤消操作。它还使用这些信息构建行的早期版本,以实现一致的读取

MVCC 的实现依赖于:隐藏字段、Read View、undo log

隐藏字段

  • A 6-byte DB_TRX_ID 用来标识最近一次对本行记录做修改 (insert 、update) 的事务的标识符 ,即最后一次修改本行记录的事务 id。 如果是 delete 操作, 在 InnoDB 存储引擎内部也属于一次 update 操作,即更新行中的一个特殊位 ,将行标识为己删除,并非真正删除。
  • A 7-byte DB_ROLL_PTR 回滚指针,指向该行的 undo log 。如果该行未被更新,则为空.
  • A 6-byte DB_ROW_ID 如果没有设置主键且该表没有唯一非空索引时,InnoDB 会使用该 id 来生成聚簇索引.

Read View

不同的事务隔离级别中,当有事物在执行过程中修改了数据(更新版本号),在并发事务时需要判断一下版本链中的哪个版本是当前事务可见的。为此InnoDB有了ReadView的概念,使用ReadView来记录和隔离不同事务并发时此记录的哪些版本是对当前访问事物可见的。

undo log

除了用来回滚数据,还可以读取可见版本的数据。以此实现非锁定读

答:
1. mysql是由mvcc实现的事务控制
2. MVCC 的实现依赖于:隐藏字段、Read View、undo log
3. 在不同的事务隔离级别下通过设置readview内容,控制了哪些数据可见于不可见

五、JVM

1、JVM 内存模型中,为什么要区分新生代和年老代,对于新生代,为什么又要区分eden 区survial区?

在这里插入图片描述

个人理解答案:

1、主流垃圾回收器cms g1都使用了分代收集算法;
2、正常系统运行时会有海量临时对象产生,这些对象短期内大部分就会失效,对于这些对象我们把他们临时放到新生代;
3、新生代满了之后需要清理垃圾对象,我们会吧有效对象复制到老年代,以便后续继续使用;
4、为了更有效的区分哪些对象应该被复制到老年代,所以在新生代划分出了eden区和s0 s1区;
5、细化后的新生代内部被再次划分以便保证高速读写同时内存连续;
【1】新对象会被保存到eden区(开始是空的所以内存连续),eden区满了会把有效对象复制到s0(s0也是空的所以也是连续空间);
【2】清空eden区(再次写入时又是连续空间)
【3】s0 和 s1在命名上互换,原来的s1等待写入(空的)
【4】eden区再次满了,重复上面步骤

文心一言AI答案:

在这里插入图片描述

2、说一下你理解的JVM原理?

JVM 运行时数据区域包含堆、栈、本地方法栈、方法区

在这里插入图片描述

在这里插入图片描述

答案:jvm是Java虚拟机,我们的class文件运行在虚拟机上,通过虚拟机解决了跨平台的问题,jvm中有jmm来管理Java内存访问的方式,不同的jvm实现性能关注有差异,现在主流的实现是Hotspot,垃圾回收器是G1,jvm运行时内存中分为方法区,堆,栈,本地方法栈,执行代码时需要执行引擎。

3、请简述一下JVM 加载 class 文件的原理机制

关键点:1. 类加载器;2. 魔数;3. 元空间:负责加载class文件,class文件在文件开头有特定的文件标示,并且ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定。

魔数

  • Class文件开头的四个字节的无符号整数称为魔数(Magic Number)。
  • 魔数是Class文件的标识。值是固定的,为0xCAFEBABE
  • 如果一个Class文件的头四个字节不是0xCAFEBABE,虚拟机在进行文件校验的时候会报错。使用魔数而不是扩展名来识别Class文件,主要是基于安全方面的考虑,因为文件扩展名可以随意更改。
    在这里插入图片描述

类加载器分为四种:前三种为虚拟机自带的加载器。

  • 启动类加载器(Bootstrap)C++

    负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类

    也叫系统类加载器,负责加载classpath中指定的jar包及目录中class

  • 扩展类加载器(Extension)Java

    负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包

  • 应用程序类加载器(AppClassLoader)Java

  • 用户自定义加载器 Java.lang.ClassLoader的子类,用户可以定制类的加载方式

工作过程:

  • 1、当AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。
  • 2、当ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。
  • 3、如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使用ExtClassLoader来尝试加载;
  • 4、若ExtClassLoader也加载失败,则会使用AppClassLoader来加载
  • 5、如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException

其实这就是所谓的双亲委派模型。简单来说:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上。
在这里插入图片描述
好处:防止内存中出现多份同样的字节码(安全性角度)
比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个 Object对象。

六、选择题

1、典型的JDBC程序按(DBECFA)顺序编写( 排序)

A.释放资源
B.获得与数据库的物理连接
C.执行SQL命令
D.注册JDBC Driver
E.创建不同类型的Statement
F.如果有结果集,处理结果集

2、下列语句哪一个正确(b)

A.Java 程序经编译后会产生 machine code
B.Java 程序经编译后会产生 byte code
C.Java 程序经编译后会产生 DLL
D.以上都不正确

3、存在使i+1<i的数吗?存在

int i = Integer.MAX_VALUE;
System.out.println(i>i+1);true

4、Integer和int的区别?

1、Integer是int的包装类,int则是Java的一种基本的数据类型;
2、integer实际是对象的引用,当new一个integer时,实际上生成一个指针指向对象,而int则直接存储数值;
3、integer的默认值是null,而int的默认值是0;

5、jsp的八个隐含对象有哪些?

关键点:

  1. jsp本质上就是servlet
  2. 答不上来关系也不大

答:

1 pageContext

类型:PageContext

代表:当前页面的上下文

作用:可以获取到页面中的其他隐含对象,同时它还是一个域对象。

2 request

类型:HttpServletRequest

代表:请求

作用:可以获取用户发送的请求信息,它也是一个域对象。

3 session

类型:HttpSession

代表:当前会话

作用:可以作为域对象,用来共享数据。

4 application

类型:ServletContext

代表:代表整个WEB应用

作用:是JavaWeb中最大的域对象。

5 response

类型:HttpServletResponse

代表:响应

作用:向浏览器发送响应信息

6 out

类型:JspWriter

代表:输出流

作用:可以向页面输出内容

7 config

类型:ServletConfig

代表:当前JSP的配置信息

作用:可以获取到Servlet标签中初始化参数

8 page

类型:Object 在service方法中有如下代码 Object page = this;

代表:代表当前JSP的对象

9 exception

类型:Throwable

代表:异常信息

作用:获取页面中的异常

6、下面程序能正常运行吗?

  1. null 是可以被强转成任何类型的;2. 静态方法不需要实例对象
public class NULL {
	public static void haha() {
		System.out.println("haha");
	}
	public static void main(String[] args) {
		((NULL)null).haha();
	}
}

七、A 系统远程调用 B 系统的接口,A 系统在完成调用之后,需要更新A 系统本地表

问题1:常见的远程调用有几种?

1. 自定义协议实现C/S RPC调用(实现复杂,需解决的问题多)
2. UDP广播类型(常见用于即时通讯类,速度快,但需要二次确认)
3. 目前主流的基于http协议调用(Restful风格的api,springcloud微服务调用使用的就是http)
4. dubbo协议(阿里出品,长连接,二进制封装数据,性能较高)
5. soap协议(古老的webservice系列框架,基于xml实现数据封装,http协议传输)
6. 异步响应式(WebFlux+Spring Data Reactive)
7. 服务器推(不主动调用,常见系统通知类)

问题2:对于有这些外部衔接的方法需要注意哪些问题?请写出注意问题及伪代码?

1、写好接口文档,方便后续维护和团队协作

2、统一化的报文结构

3、标准化的服务状态码

 status_code 200;//请求成功

4、统一化请求日志记录及异常记录

GlobalExceptionHandler...
logger.error("服务异常",exception);

5、当请求延迟过高,可以快速失败
6、重试机制

// 服务列表
serverList = {ser1,ser2,ser3}
retrycount = 0;
retrymax=10;
maxrequesttime = 200ms;
getxxoo(){
    try{
    // 尝试请求数据
    calldata(serverList)
    }catch (请求失败 500类异常 || 请求超时 calldata的网络请求方法中){
	 	// 拦截器记录日志
	    serverList.remove(刚才请求的服务器)
	 	// 重试次数过多
	    if (retrycount == retrymax)
	   	return "当前访问不可用稍后再试"
	    retrycount ++;
	    递归调用本方法
    }
}

7、事务问题,可回滚

getData(){
	分布式事务开启

	get1();
	get2();
	get3();
	事务结束
	要么全成功 要么全失败
	修改数据时使用 tryModify() 临时保存数据或通过Seata类似的框架实现
}

8、数据一致性问题

//有并发修改数据时,如果需要保证一致性,需要使用分布式锁
//修改方法
modifyxx(){
	// 尝试加锁
	boolean haslock = tryLock(id)
	if(haslock){
		httppost(url,data)
		releaseLock(id)
	}
	else{
		// 提示用户一会再试试
		// 尝试再次获取锁
	}
}

八、在如下代码中,当调用insertA 方法的时候,是否能在当insertA 方法调用insertB的时候,如果insertB 插入b表的时候出现异常,能否保证 insertA中的a 表插入成功,如果不能,应该如何修改。

@Service
@Transactional
public class TestServie {

	@Autowired
	private JdbcTemplate jt;
	
	public void insertA(){
		jt.execute("insert into a(m,n)values(1,2)");
		insertB();
	}
	public void insertB(){
		jt.execute("insert into b(h,i)values(1,2)");
	}
}

答案:不能,在类上使用了@Transactional注解,默认开启了全局读写事务,因此可以将@Transactional加在方法上即可。

九、数据库三范式是什么?

1、第一范式:单表(字段)拆分到不可拆分为止【有主键,具有原子性,字段不可分割】;
2、第二范式:每一行数据唯一性;
3、第三范式:单行数据中保留唯一主键,建立外键关联表;

答案:
1. 数据库三范式是设计数据库表的方法论,能够充分的利用关系型数据库把实体有机的关联起来
2. 降低耦合度节省存储空间

十、浅谈ReentrantLock的设计

  1. ReentrantLock 是在多线程竞争资源时使用的锁,他是一个独占锁、可重入锁,也是悲观锁
  2. ReentrantLock 支持公平锁,对公平和非公平锁有不同的实现逻辑
  3. ReentrantLock 使用 aqs(AbstractQueuedSynchronizer)来实现的获取锁的线程队列等待的过程
  4. 内部使用了原子操作类 cas 比较线程与对应的锁关系
  5. 内部支持newCondition来灵活的控制获取到锁的线程的阻塞与释放

十一、值传递和引用传递问题

关键点:1. 引用传递;2. 堆栈内存分析

public class demo01 {
    public static void main(String args[]) {
        StringBuffer a = new StringBuffer("A");
        StringBuffer b = new StringBuffer("B");
        operater(a,b);
        System.out.println(a+" "+b);// AB B
    }
    public static void operater(StringBuffer x, StringBuffer y) {
    	// x 是一个列表对象,x.append(y) 实际上是在修改了 x 对象本身,而不是替换整个对象。因此,当您在 operater 方法中调用 x.append(y),x 列表会被修改为 ['A', 'B']。由于 a 和 x 引用同一个对象,它们指向同一个内存地址。所以当您在 operater 方法中修改了 x,也会影响到 main 方法中的 a
        x.append(y);
        // 将x赋值给了y,这意味着y也会引用"AB"。然而,需要注意的是,这个赋值操作只会在operater方法内部起作用,并不会影响到main方法中的b对象。
        y = x;
        System.out.println(x+" "+y);// AB AB
    }
}

十二、多线程

1、多线程中 start()方法和 run()方法的区别是什么?

答:
1. start用来启动线程,改变的是线程的状态,由就绪进入执行
2. run方法中包含要执行的代码,在执行状态时运行里面的代码,方法返回值是void

2、创建线程有几种方式?

(1)使用Thread类创建线程

public class MyThread extends Thread {  
    public void run() {  
        System.out.println("使用thread方式创建线程"); 
    }  
}  
// 创建并启动线程  
MyThread thread = new MyThread();  
thread.start();

(2)使用Runnable接口创建线程

public class MyRunnable implements Runnable {  
    public void run() {  
        System.out.println("使用Runnable方式创建线程");  
    }  
}  
// 创建并启动线程  
MyRunnable runnable = new MyRunnable();  
Thread thread = new Thread(runnable);  
thread.start();

(3)使用Executor框架创建线程

import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
  
public class MyThread implements Runnable {  
    public void run() {  
        System.out.println("使用ExecutorService方式创建线程");
    }  
    public static void main(String[] args) {  
        // 创建线程池  
        ExecutorService executor = Executors.newFixedThreadPool(10);  
        // 提交任务到线程池  
        executor.submit(new Mythread());  
        // 关闭线程池  
        executor.shutdown();  
    }  
}

3、简单写一个会导致死锁的程序

  1. 获得锁后不释放,其他线程一直拿不到锁
  2. 解决:不要嵌套获得多个锁
	static Object lockA = new Object();
    static Object lockB = new Object();

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread() + " 尝试获取锁A");
                synchronized (lockA){
                    System.out.println(Thread.currentThread() + " 获取到了锁A");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(Thread.currentThread() + " 尝试获取锁B");
                    synchronized (lockB){
                        System.out.println(Thread.currentThread() + " 获取到了锁B");
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread() + " 尝试获取锁B");
                synchronized (lockB){
                    System.out.println(Thread.currentThread() + " 获取到了锁B");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(Thread.currentThread() + " 尝试获取锁A");
                    synchronized (lockA){
                        System.out.println(Thread.currentThread() + " 获取到了锁A");
                    }
                }
            }
        }).start();
    }

4、多线程变量同步

  1. 共享变量在多线程读取的时候,会被拉倒线程本地,white 在执行时,一直使用的都是本地变量的值,所以后续更改,线程内一直访问不到最新变量,程序会卡死
  2. 给变量增加 volatile关键字,保证多线程之间 变量可见性
public class ThreadSafeCache {

	private int result;

	public int getResult() {
		return result;
	}

	public synchronized void setResult(int result) {
		this.result = result;
	}

	public static void main(String[] args) {
		ThreadSafeCache threadSafeCache = new ThreadSafeCache();

		for (int i = 0; i < 8; i++) {

			new Thread(() -> {
				while (threadSafeCache.getResult() < 100) {

				}
				System.out.println("我执行了");
			}).start();
		}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			threadSafeCache.setResult(200);
	}
}

5、定义了一个类T,其中定义了一个synchronized 方法do(); A=newT();B = new T()。当一个线程进入A对象的 do 方法后,另一个线程是否可进入B对象的do 方法?互不影响

1. synchronize 普通方法,锁的是当前对象
2. synchronize 静态方法,锁的是class
3. 同步代码块,可以手动指定锁对象是啥

6、多线程有几种实现方法,都是什么?

  1. 实现Runnable接口 void返回值
  2. 实现Callable接口 可以指定返回值
/**
 * 1. 创建Callable的实现类,并重写call()方法,该方法为线程执行体,并且该方法有返回值
 */
class MyCallableThread implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "执行了!");
        return 200;
    }
}

public class CallableDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 2. 创建Callable的实例,并用FutureTask类来包装Callable对象
        // 3. 创建FutureTask对象,需要一个Callable类型的参数
        FutureTask task = new FutureTask<Integer>(new MyCallableThread());
        // 4. 创建多线程,由于FutureTask的本质是Runnable的实现类,所以第一个参数可以直接使用task
        new Thread(task, "threadName").start();
        //new Thread(task, "threadName2").start();
		
        /*while (!task.isDone()) {
            System.out.println("wait...");
        }*/
        System.out.println(task.get());
        System.out.println(Thread.currentThread().getName() + " over!");
    }
}

7、编写一个基于线程安全的懒加载单例模式

关键点:1. 多线程访问;2. 防止直接new对象;3. 使用锁;4. 内部类加载实现、cas实现等

public class Test03 {
    private Test03(){}

    private static Test03 instance = null;

    public static Test03 getInstance(){
        //有可能在多线程访问的时候 重复new了对象
        if(instance == null){
            // 有可能有多个线程 进入抢锁等待状态
            synchronized (Test03.class){
                if (instance == null){
                    instance = new Test03();
                }else {
                    return instance;
                }
            }
        }
        return instance;
    }
}

十三、对于高并发、高可用问题的常用处理方式

1、对于高并发

关键点:

  1. 寻找瓶颈
  2. 分治思想,业务拆分,流程拆分
  3. 扩容
  4. 限流
  5. 分流 ,cdn 缓存
  6. 流量清洗 waf
  7. 多级缓存设计 后端缓存,客户端缓存
  8. 日志溯源
  9. 资源隔离
  10. 弹性扩缩容
  11. 降级处理 前后端 兜底数据

2、对于高可用

  1. 容器化管理 HA
  2. keepalived

十四、哪一个List实现了最快插入?

arraylist :数组实现的,查询,修改比较快
linkedlist:链表实现,插入,删除比较快,直接在最后插入数据即可
vector:jdk1.0就有 线程安全,效率特别低

十五、同步有几种实现方法,都是什么?

非阻塞

1. volatile
2. cas及atomic系列实现

阻塞

1. wait()
2. sleep
3. synchronized
4. Lock 的实现
   1. ReentrantLock
   2. ReentrantReadWriteLock 等
   3. condition.await()
5. CountDownLatch
6. CyclicBarrier
7. Semaphore
8. BlockingQueue

十六、SpringBoot

1、springboot是如何管理版本依赖的?

1、springboot底层使用Maven管理依赖,通过控制pom.xml父子关系来完成细节配置,在父pom中定义具体框架和版本号以及额外的信息;
2、提供了很多场景的spring-boot-starter的pom.xml文件,来标准化的引入依赖避免冲突;

2、什么是自动配置?

关键点:

1. 看springboot的源码
2. @SpringBootApplication 中包含的@EnableAutoConfiguration,@SpringBootConfiguration,@ComponentScan 注解
3. @EnableAutoConfiguration 开启自动配置功能 内部还包含 @AutoConfigurationPackage、@Import
   1. @AutoConfigurationPackage 中 @Import(AutoConfigurationPackages.Registrar.class) 引入了 Registrar.class 完成批量注册,默认扫描主启动类的包@Bean或者@Compont等注解
   2. @Import(AutoConfigurationImportSelector.class)
4. @ComponentScan 扫描被@Compent(@Service@Controller)注解的bean 加载到容器中
5. @SpringBootConfiguration 表示这是一个SpringBoot的配置类

答:

1. 所加载使用的jar包 如果是比较常见的,spring都提供了默认配置,也就是不像以前一样需要把框架的每一个属性都要配置一遍,主要目的是简化开发
2. springboot 通过在启动类上添加注解 @SpringBootApplication 完成自动配置
3. 内部完成了读取每个jar包下的`META-INF/spring.factories`和spring-boot-autoconfigure-2.6.7.jar中的默认配置

3、起步依赖?

指的是各种starter重点是pom.xml,其中包含了框架所需要的其他依赖以及默认配置文件,不需要我们手动配置了。

4、什么是Spring的依赖注入?有哪些方法进行依赖注入?

依赖注入是指将依赖的对象实例交给spring帮我们注入管理,从而释放对对象的管理权,比如可以统一替换接口的实现,更高效的开发程序。
1、set方法注入;2、构造方法注入;3、@Autowired【用于自动装配bean,它可以根据类型进行注入】和@Resource【用于获取指定名称的bean,它可以根据名称进行注入】

5、Spring的AOP的使用情景有哪些?简述其实现原理

在这里插入图片描述

ADG同步性能优化:如何正确配置standby redolog避免WAIT_FOR_LOG状态 本文深入剖析了Oracle ADG(Active Data Guard)同步中常见的WAIT_FOR_LOG状态,指出其根源在于Standby Redo Log(SRL)配置不当。文章提供了从诊断到优化的完整实践指南,重点阐述了SRL大小匹配、组数充足等黄金配置法则,帮助架构师从根本上避免同步延迟,实现稳定高效的实时数据同步。 阅读详情

相关推荐

使用DeepSeek、MCP和AKShare实现智能金融问答系统技术方案

DeepSeek是由深度求索公司开发的大规模语言模型,最新版本DeepSeek-V3采用混合专家(MoE)架构,拥有671B参数,激活37B参数,在多项基准测试中表现优异3。要使用DeepSeek的API服务:访问DeepSeek平台注册账号获取API Key(形如AKShare是基于Python的金融数据接口库,提供股票、基金、期货、宏观经济等领域的海量数据。主要特点包括:免费开源,数据源丰富支持多种数据格式(DataFrame/JSON)持续更新维护安装命令。

Kin 3170

MySQL优化篇:排序分组优化

文章目录1、order by关键字排序优化1.1 无过滤不索引1.2 顺序错,必排序1.3 方向反,必排序1.4 索引的选择1.5 using filesort1.6 使用覆盖索引1.7 总结2、GROUP BY关键字优化 where 条件和on的判断这些过滤条件,作为优先优化的部分,是要被先考虑的。其次,如果有分组和排序,那么也要考虑group by 和order by。 1、order by...

HTZW的博客 2024

Proteus仿真实战:基于IIC驱动SSD1306的0.96英寸OLED显示方案解析

本文详细解析了在Proteus仿真环境中基于IIC驱动SSD1306的0.96英寸OLED显示方案。从硬件搭建、IIC接口连接、软件驱动移植到常见问题排查,提供了全面的实战指导,帮助开发者快速实现OLED显示功能并优化性能。

weixin_28724661的博客 769

order by使用索引列排序时会失效吗?

order by使用索引列排序时会失效吗? 在使用order by对某列进行排序时, 其sql一定进行了多表联查的操作. 说白了肯定做了表关联. 既然有表关联, 那order by排序就可以对任意的表进行排序. 那么应该对那个表进行排序好点呢? 先说结论, order by后面跟的索引列只是对 驱动表才起作用, 也就是说如果是对驱动表进行排序, 那么order by后面的索引是起作用的, 但是如果order by后面跟的排序字段不是驱动表的, 那么这时索引是不起作用的. 问题来了 , 什么是驱动表?

libingbojava的博客 6077

群晖Lucky套件高级玩法-——更新证书同步更新群晖自带证书

群晖Lucky套件高级玩法-——更新证书同步更新群晖自带证书

wojuzi的博客 2448

TexGen模型导出到ABAQUS的inp文件:如何快速修改纱线材料属性(避坑指南)

本文针对TexGen模型导出到ABAQUS的inp文件后纱线材料属性缺失或错误的问题,提供了高效的解决方案。文章详细解析了inp文件结构,指导用户如何手动定位并修改纱线材料属性,并提供了可批量处理的Python脚本,帮助用户快速、精准地完成材料参数赋值,有效提升复合材料仿真工作效率。

ice55的博客 600

order by 索引是否一定会走索引

order by 索引是否一定会走索引和优化问题。

Fanzongshen的博客 9374

联想服务器ThinkSystemRAID阵列设置教程

关注我不迷路,全是干货! 以联想ThinkSystemSR530为例子进行示范。 开机点按【F1】 点击——【UEFI设置】 依次点击——【系统设置】——【存储】 点击——【RAID卡】 PS:本次服务器配置的是730-8i 阵列卡,按实际情况选中需要设置的阵列卡即可。 点击——【Main Menu】 点击——【Configuration Management】 点击——【Create Virtual Drive】 点击——【Select RAID Leve..

littlelotusK的博客 2万+

order by两种排序方式

order by两种排序方式

weixin_43442127的博客 1795

ENSP:小型企业网络拓扑设计

包含的技术:ospf、dhcp中继、ac+ap、vrrp+mstp、acl、浮动路由、静态路由、vlan划分

weixin_45921302的博客 1万+

UG\NX二次开发 获取对象的层、颜色、隐藏状态、线宽、线型、高亮显示状态

获取对象的层、颜色、隐藏状态、线宽、线型、高亮显示状态。

王牌飞行员_里海的博客 1980

MySql使用order by会不会走索引?

需要判断查询的返回字段是否被索引覆盖, 如果全部被索引覆盖了那么就会走索引,如果没有全部覆盖mysql 就会根据数据量的大小来判断是否进行全表扫描或者先走索引再回表查询。本文引用:mysql使用order by会不会走索引?_骑电动车的小黄的博客-优快云博客。

xiaoshitou_2015的博客 2649

YOLOv11-seg改进系列 | 引入CVPR2022 MetaFormer,零参数池化Token混合+StarReLU MLP,精度涨不掉速

本文提出了一种改进YOLOv11分割任务的C3k2_PoolingFormer模块,通过引入MetaFormer架构和Pooling Token Mixer,在保持模型轻量化的同时增强全局感受野建模能力。核心创新包括:1)使用零参数的AvgPool3×3差值作为Token Mixer,实现高效邻域信息聚合和局部对比增强;2)采用StarReLU MLP替代传统激活函数,提升非线性表达能力。改进后模型仅增加6.1%参数量,却能显著提升分割精度,特别适用于需要长程依赖建模的实例分割任务。该设计为轻量级视觉模型提

qq_44224801的博客 431

面试 Linux 运维工作至少需要知道哪些知识?

原文转自: https://mp.weixin.qq.com/s/zOipo4Usu2vj76ENEmZI9A 知乎上有这样一个问题:一个新手面试 Linux 运维工作至少需要知道哪些知识?其中有一个答案对这一话题的解读非常深入,今天特别分享给大家。 一、什么是大型网站运维? 首先明确一下,全文所讲的”运维“是指:大型网站运维,与其它运维的区别还是蛮大的;然后我们再对大型网站与小型网...

mysteryflower的专栏 316

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

2026软件测试面试题-mysql

触发器是一种在数据库中执行自动化操作的工具,是一种特殊类型的存储过程,通过数据库事件来自动触发运行的(如INSERT、UPDATE、DELETE操作),主要是没有人工干预的情况下来完成复杂度高一些的约束条件,从而保证数据库的完整性和一致性。作用:数据约束:触发器可以强制执行数据库表的基本约束。如必填字段或唯一值约束等,如果违反他们,触发器会阻止插入、更新或删除操作。数据校验:触发器可以校验数据是否符合业务规则或限制。例如,当尝试插入一条将来日期时,触发器会触发并阻止该操作。

2401_83396023的博客 929

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

索引总结(2)

删除之后如果重启,会从最大的id开始递增如果没重启,会延续删除之前最大的id开始递增第一次 取回id,第二次(回表)根据id拿到完整数据第一次 取回id,第二次(回表)根据id拿到完整数据select age from user where age >20 and name like"张%";覆盖索引不会回表查询,查询效率也是比较高的为c2和c3列建立联合索引,如下所示:where c3=?

莫等闲 白了少年头 空悲切 865

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

MySQL排序(Order By)为什么要使用索引

MySQL排序(Order By)为什么要使用索引 1. WHERE条件句中使用索引 以查询一条程咬金 记录为例: 创建索引 先创建一个二级索引 不选择索引字段做条件查询 key=null 执行计划中没有用到索引 rows=69 全表扫描 使用索引字段作为条件查询 key=name_index 使用到索引name_index rows=1 对比结论 在选条件语句中不加索引字段,索引会失效,包括聚簇索引。 使用的索引避免了全表扫描 2. Ord...

轩1024的博客 1万+

MySQL利用索引优化ORDER BY排序语句的方法

create [unique|fulltext|spatial] index 索引名 on 表名(字段名 [长度] [asc|desc]);建立索引(uid,x,y)实现order by的优化,比建立(x,y,uid)索引效果要好得多。注意:如果columnX对应多个值,如下面语句就无法利用索引来实现order by的优化。在[sort]这个栏位上建立索引就可以实现利用索引进行order by 优化。建立一个联合索引(columnX,sort)来实现order by 优化。在已有的表创建索引语法。

qq_58626489的博客 768

Spring AI + GPT-5.5 + Ollama 配置教程:Base URL、超时与流式调用

由于不同 Spring AI、Spring Boot 小版本之间仍可能存在差异,创建项目时应检查 Spring Initializr、Spring AI BOM 和官方兼容矩阵,不要直接复制旧教程中的 Starter 名称和版本号。多人项目最好隔离不同客户端,并在脱敏前提下记录最终 URL、状态码、请求耗时、请求 ID 和模型 ID。Spring AI 接入模型 API,至少要同时确认 Starter、Base URL、请求路径、API Key、模型 ID、连接超时、读取超时和流式客户端这 8 项。

2601_95893075的博客 215

V8 机制、手写核心函数与 TypeScript 类型体操

或固定初始化(如数组先定长、对象先给全字段)保持类型与形状稳定;这些都比"换框架"更基础。只能处理纯数据(丢函数、Date、RegExp、循环引用报错)。生产级深拷贝要处理:原始值短路、循环引用、V8(Chrome / Node 的 JS 引擎)不是"解释一行跑一行"那么简单,它用。图:V8 执行流程——解释执行 + 热点优化,优化失败会 Deopt 回退。JS 内存自动管理,但"自动"不等于"不会漏"。是"固定间隔最多执行一次"。手写 Promise 是"懂异步"的试金石。是"停下后才执行最后一次",

qq_38468358的博客 325

【JVM】对象内存布局

HotSpot JVM 中,Java 对象内存布局由对象头(12字节,含Mark Word与压缩Klass Pointer)、实例数据及对齐填充构成,总大小为8字节倍数。对象头支持锁状态动态复用,指针压缩使引用仅4字节,但堆超32GB时失效。实例字段按类型优先级重排序以减少间隙,最小对象大小为16字节。通过JOL工具可精准验证布局,理解锁机制、GC、伪共享等底层行为。

2301_79732484的博客 140

Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

要努力去发光,而不是被照亮~ 112

Spring Boot 数据源与 MyBatis(-Plus) 自定义配置详解

本文详解 Spring Boot 中单数据源环境下 HikariCP 与 MyBatis-Plus 的自定义配置。通过手动声明 SqlSessionFactory,实现下划线转驼峰、日志输出、一级缓存策略等精细化控制。结合 HikariCP 核心参数调优(如最大连接数、连接生命周期),确保高性能与稳定性。适用于仅需访问单一数据库的场景,避免多数据源复杂性,兼顾性能与可维护性。

BADAO_LIUMANG_QIZHI的博客 190

LeetCode Hot 100 二叉树专题(二)3 题(Java)

本篇文章共 3 题:543. 二叉树的直径、102. 二叉树的层序遍历、108. 将有序数组转换为二叉搜索树。 每道题都统一按「① 题目分析 & 解题思路 → ② 常见解法(附代码)及讲解 → ③ 知识点总结」的顺序组织;代码使用 Java 编写,节点定义沿用 LeetCode 默认的 TreeNode。

2401_88612756的博客 352

Decorator

TaskDecorator 是异步场景下"跨线程传递上下文"的标准方案,主要用于传递 MDC、用户信息、数据源路由等上下文数据,核心价值是让异步任务的日志链路不中断、业务上下文不丢失。TaskDecorator 是 Spring 提供的一个钩子接口,用于在异步任务执行前对 Runnable 进行包装,常用于跨线程传递上下文。如果你在项目中遇到具体的异步上下文传递问题,可以把代码贴出来,我帮你给出最合适的 Decorator 方案 👍。✅ 核心能力:在线程切换时,把"父线程的上下文"搬到"子线程"

wlwork66的博客 102

JDK 下载安装:装完 Java 提示「不是内部或外部命令」?环境变量没配

JDK 是写 Java 程序必须装的东西。它包含运行 Java 的虚拟机(JRE)和编译 Java 的编译器(javac)——装了它,能跑、.java文件能编译成可执行程序。免费,学习和小规模生产都不花钱。

科小怪的博客 608
上一篇: 【Jenkins入门到实战】忽如一夜春风来,千树万树梨花开
下一篇: 【软考】系统集成项目管理工程师(一)信息化基础知识【6分】
智汇风渔AI小白
博客等级 码龄7年 1万+粉丝 179原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智汇风渔AI小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值