面试题

面试题

请用代码写一个单例模式、策路模式、模板模式,并用代码写出如何使用

单例模式

1
2
3
4
5
6
7
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}

策略模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface Strategy {
void algorithmInterface();
}
public class ConcreteStrategyA implements Strategy {
@Override
public void algorithmInterface() {
// 算法A
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void algorithmInterface() {
// 算法B
}
}
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void contextInterface() {
strategy.algorithmInterface();
}
}

模板模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public abstract class AbstractClass {
public void templateMethod() {
specificMethod();
abstractMethod1();
abstractMethod2();
}
public void specificMethod() {
// 具体方法
}
public abstract void abstractMethod1();
public abstract void abstractMethod2();
}
public class ConcreteClass extends AbstractClass {
@Override
public void abstractMethod1() {
// 具体实现
}
@Override
public void abstractMethod2() {
// 具体实现
}
}
public class ConcreteClass2 extends AbstractClass {
@Override
public void abstractMethod1() {
// 具体实现
}
@Override
public void abstractMethod2() {
// 具体实现
}
}

有user、user_login_log两张表,user表有100行数据,user_login_log表有1亿行数据,其他信息见下面的建表语句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
create table user_login_log (
id bigint(20) not null auto_increment,
user_id bigint(20) not null,
login_type tinyint(4) not null comment '登录类型:1-密码登录,2-验证码登录',
create_time datetime not null,
primary key (id)
key idx_userid1 (create_time)
key idx_userid2 (user_id, login_type, create_time)
) engine=InnoDB default charset=utf8mb4;

create table user (
id bigint(20) not null auto_increment,
user_name varchar(32) not null comment '姓名',
primary key (id)
) engine=InnoDB default charset=utf8mb4;

写一条SQL,要求查询昨天登录次数前10名的用户名称、并按照次数倒序,要求速度足够快

1
2
3
4
5
6
7
select u.user_name, count(1) as login_count
from user_login_log l
join user u on l.user_id = u.id
where l.create_time >= '2021-07-28 00:00:00' and l.create_time < '2021-07-29 00:00:00'
group by l.user_id
order by login_count desc
limit 10;

写一条SQL,要求查询昨天loginType=1的用户名称,要求速度足够快。如有性能问题,要怎么修改索引

修改索引idx_userid2(user_id, login_type, create_time)idx_userid2(login_type,create_time)

1
2
3
4
select u.user_name
from user_login_log l
join user u on l.user_id = u.id
where l.login_type = 1 and l.create_time >= '2021-07-28 00:00:00' and l.create_time < '2021-07-29 00:00:00';

String和StringBuilder、StringBuffer的区别

  1. String是不可变的,每次修改都会生成新的对象,浪费内存,而StringBuilder、StringBuffer是可变的,修改时不会生成新的对象。
  2. StringBuffer 是线程安全的,而StringBuilder 则没有实现线程安全功能,所以性能略高。

改造User,达到可以使用User做key,User的userName做value,使用HashMap 来存储,当userid一样就认为是同一个对象,user对象如下,请写出改造后的User

重写hashCode()equals()方法

1
2
3
4
5
public class User {
private Long userId;
private String userName;
// getter、setter
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class User {
private Long userId;
private String userName;
// getter、setter
@Override
public int hashCode() {
return Objects.hash(userId);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof User) {
User user = (User) obj;
return userId.equals(user.userId);
}
return false;
}
}

请设计一个学校管理系统的实体关系(可画ER图,也可以用文字描述》,需要包含每个实体的关键属性字段和实体间的关系,需求如下

  1. 学校有若干系,每个系有若干班级,每个班级有若干学生,每个学生可以选修若干门课程
  2. 每个系有若干老师,每个老师都要教几门课程,一个课程只会让一个老师教
erDiagram
    school o|--|{ tie : "1:N"
    tie o|--|{ class : "1:N"
    tie o|--|{ teacher : "1:N"
    class o|--|{ student : "1:N"
    student }|--|{ course : "N:N"
    teacher o|--|{ course : "1:N"

有以下HashMap,需要按照value来排序,并将key打印到控制台

1
2
3
4
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 5);
map.put("c", 3);
1
map.entrySet().stream().sorted(Map.Entry.comparingByValue()).map(Map.Entry::getKey).forEach(System.out::println);

设计一个系统间接口调用的安全请求规则,要求能做到防篡改,高性能,具备时效性,请用文字描述实现流程

  1. 使用请求参数+时间戳+盐使用MD5加密生成签名
  2. 请求时带上签名和时间戳
  3. 服务端校验时间戳是否过期,校验签名是否正确

实现一个点击计数功能,统计每个IP的请求次数,做到高并发、准确Xmx=128M,请描述有几种方案

  1. 使用ConcurrentHashMap,使用ip作为key,使用AtomicInteger作为value,使用putIfAbsent方法来保证原子性
  2. 使用Redis,使用ip作为key,使用incr方法来保证原子性

一个部署在linux服务中的JAVA服务CPU占用一直是100%,请写出排查步骤,要求找到导致CPU100%的代码行

方法一

  1. 使用top命令查看CPU占用最高的进程
  2. 使用jstack命令查看进程的线程堆栈
  3. 使用jmap命令查看进程的内存使用情况
  4. 使用jstat命令查看进程的GC情况
  5. 使用jmap命令生成heap.bin文件,使用jhat命令分析heap.bin文件

方法二

  1. top 查看哪个占用高
  2. top -H -p PID 查询具体的线程
  3. printf "%x\n" tid 将需要的线程ID转换为16进制格式(tid是上一条命令查询出来的)
  4. jstack pid | grep tid -A 50 通过jstack查看这个线程现在在执行的东西

使用多线程实现一个批处理过程,将以下数组,按10个数据一组,每组1个线程打印数据,并在10个线程都处理完成后输出总打印次数

1
2
3
4
int[] arr = new int[100];
for (int i = 0; i < 100; i++) {
arr[i] = i;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int[] arr = new int[100];
for (int i = 0; i < 100; i++) {
arr[i] = i;
}
AtomicInteger count = new AtomicInteger();
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
int finalI = i;
executorService.execute(() -> {
for (int j = finalI * 10; j < finalI * 10 + 10; j++) {
count.getAndIncrement();
}
});
}
executorService.shutdown();
while (!executorService.isTerminated()) {
}
System.out.println(count.get());

相关文章

Java框架面试题

Java基础面试题

JVM-虚拟机栈面试题

JUC-JVM面试题