Java-杂谈

Java-杂谈,第1张

Java-杂谈 2021-11-25 1 线程安全方面的集合?

1、 Vector,Vector性能最差,所有的方法都是加了synchronized来同步,从而保证线程安全
2、 SynchronizedList是Collections类的静态内部类,它能把所有容器集合转换成线程安全的,比 Vector 有更好的扩展性和兼容性。
3、 CopyOnWriteArrayList是java1.5以后才加入的新类,从命名可以理解为复制在写入的List。
它的添加时加锁的(ReentrantLock ,非synchronized同步锁),读 *** 作是没有加锁。

2 hashmap怎么转为线程安全?

场景:以前的业务实现就是一个hashmap,现在要保证线程安全如何实现?
答:可以使用Collections类,它能把所有的容器转换成线程安全的。

3 请问用过ConcurrentHashMap源码吗?知道它用了哪些锁吗?

答:CAS与synchronized来保证线程安全。

4 CAS原理,CAS中的一些经典问题?ABA

CAS原理:读取内存值,修改,然后比较内存中的值是否被修改,如果没有就把修改的值更新回内存。如果内存中的值被修改就重新读取内存中的值,进入下一次循环(自旋)

5 java怎么实现解决ABA问题?

答:AtomicStampedReference类,
Java中使用AtomicStampedReference来解决CAS中的ABA问题,它不再像compareAndSet方法
中只比较内存中的值也当前值是否相等,而且先比较引用是否相等,然后比较值是否相等,这样就避免了ABA问题。
解决 ABA 问题的原子类:AtomicMarkableReference(通过引入一个 boolean
来反映中间有没有变过),AtomicStampedReference(通过引入一个 int 来累
加来反映中间有没有变过)

6你项目用redis主要做什么?redis应用场景 7 redis持久化方式?rdb与aof?

redis数据持久化,为了解决系统宕机后进行数据恢复。
1、RDB:默认存储方式,Rdb可以手动触发(save,与bgsave),周期性触发,redis启动默认开启Rdb数据持久化。Rdb相当于给内存拍一个快照以dump.rdb文件形式存储在本地。优点:适合做冷备。恢复数据快;
2、aof:把redis写 *** 作指令以appendonly.aof文件的方式保存在本地;优点:备份精确不会出现数据丢失,缺点:恢复数据慢,可能日志文件很大,浪费本地磁盘空间。

8 rdb与aof最大的区别?

1、存储方式不同,rdb是以dump.rdb文件存储,而aof是以appendonly.aof形式存储。
2、恢复数据方式不同:rdb恢复数据直接把文件加载到内存,而aof是从新去执行一遍日志记录的指令。

9 jvm问题?怎么判断一个对象要被回收?

引用计数:每个对象中有一个计数器记录着对象被引用的次数,当为0的时候说明没有被引用,就会被标记回收。
可达性分析:从根节点开始去搜索存在引用的对象,如果在jcRoots中不会被回收,相反会被回收
1、当然判断一个对象是否被回收是引用计数器是否为0,
2、是否被一个可达对象所引用。
3、是否在根集中

10 可达性算法中有一个概念叫GC roots知道吗?

jcRoots就是根集,在根集中的对象不会被回收,

11 哪些对象可以被作为垃圾回收的根节点?

虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中的常量引用的对象
方法区中的类静态属性引用的对象
本地方法栈中 JNI(Native 方法)的引用对象
活跃线程(已启动且未停止的 Java 线程)

12 一个接口有多个实现的情况,怎么去解决注入对象的准确性?

@Primary注解
@Qualifier注解来解决实现冲突的问题。

13 如果不想用注解去解决还有其他的实现方式吗? 14 在某个service中想要拿到容器对象怎么做?

使用Aware接口下面的实现类
ApplicationContextAware接口拿到容器对象。

15 微服务项目中用到哪些组件?

Eureka作为服务发现,config配置中心,Zuul网管,feign服务之间调用。

16 sping config存在什么问题?

刷新配置需要手动刷新。结合rabbitmq bus
刷新过程,当我们在git上修改了配置,然后通过rabbitmq下发刷新指令,服务收到刷新指令之后去注册中心找到配置中心的地址,在配置中心下载自己的配置。配置中心在git上下载服务配置。

17 用户携带token,在zuul网关需要校验token,怎么自定义逻辑?

实现ZuulFilter类,
1、filterType()方法中选择过滤器类型权限校验使用pre类型的过滤器;
2、在shouldFilter()选择需要权限校验的服务
3、在run()方法中实现过滤逻辑,过滤逻辑就是获取请求上下文对象,拿到用户携带的token做判断。

@Component
public class AccessFilter extends ZuulFilter {
    // 设置过滤器的类型:pre, routing, post, error
    @Override
    public String filterType() {
        // return "pre";
        return FilterConstants.PRE_TYPE;
    }

    // 设置顺序号
    @Override
    public int filterOrder() {
        // 前置过滤器中有5个默认的过滤器,自定义过滤器放到末尾
        // 第5个过滤器中,向上下文对象放入了 serviceId
        // 后面过滤器中才能访问这个数据
        return 6;
    }
    
    @Override
    public boolean shouldFilter() {
        

        // 获得一个请求上下文对象
        RequestContext ctx = RequestContext.getCurrentContext();
        // 从上下文对象获得调用的后台服务的 serviceId
        String serviceId =
            (String) ctx.get(FilterConstants.SERVICE_ID_KEY);// "serviceId"
        // 如果调用的是 item-service,返回true
        return "item-service".equals(serviceId);
    }
    // 过滤代码
    @Override
    public Object run() throws ZuulException {
        // http://localhost:3001/item-service/iuy4tgf3?token=uy4t34t
        // 获得上下文对象
        RequestContext ctx = RequestContext.getCurrentContext();
        // 获得 request 对象
        HttpServletRequest request = ctx.getRequest();
        // 接收 token 参数
        String token = request.getParameter("token");
        // 如果 token 不存在: null, "", "    "
        if (StringUtils.isBlank(token)) {
            // 阻止继续调用
            ctx.setSendZuulResponse(false);
            // 直接返回响应
            // JsonResult - {code:400, msg:未登录, data:null}
            String json = JsonResult
                                .build()
                                .code(400)
                                .msg("Not Login! 未登录!")
                                .toString();
            ctx.addZuulResponseHeader(
                    "Content-Type", "application/json;charset=UTF-8");
            ctx.setResponseBody(json);
        }

        return null; //zuul当前版本这个返回值不起任何作用
    }
}
18 zuul相对于gateway的缺点有哪些?

zuul的局限性,底层使用了servlet,存在阻塞IO的问题,gateway使用了netye。

19 rabbitmq怎么保证消息可靠性?

1、生产者丢失消息:从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和/confirm/i模式来确保生产者不丢消息;
2、消息队列丢数据:消息持久化。
处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。
这个持久化配置可以和/confirm/i机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。
这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。
那么如何持久化呢?
这里顺便说一下吧,其实也很容易,就下面两步
将queue的持久化标识durable设置为true,则代表是一个持久的队列
发送消息的时候将deliveryMode=2
这样设置以后,即使rabbitMQ挂了,重启后也能恢复数据
3、消费者处理消息成功后,手动回复确认消息。

20 rabbitmq怎么实现手动确认?

手动确认就是消息消费完之后给队列一个回执,消息队列收到回执后确认消息被消费,才会删除消息。否则回进行消息回滚把消息分配给其他消费者
//定义一个新的队列,名为 task_queue
//第二个参数是持久化参数 durable
ch.queueDeclare(“task_queue”, true, false, false, null);

//第三个参数设置消息持久化
ch.basicPublish("", “task_queue”,
MessageProperties.PERSISTENT_TEXT_PLAIN,
msg.getBytes());

2021-11-29 1 分布式事务有做过吗? 2 网管用的什么? 3 你在项目中怎么保证线程安全? 4 购物车怎么设计订单过期时间? 5 RabbitMq数据流转过程? 6 sheep与waite有什么区别?

最大的不同是在等待时 wait 会释放锁,而 sleep 一直持有锁。Wait 通常被用于线
程间交互,sleep 通常被用于暂停执行。
yield()方法仅释放 CPU 执行权,锁仍然占用,线程会被放入就绪队列,会在短时
间内再次执行。

wait()方法会释放 CPU 执行权 和 占有的锁。
sleep(long)方法仅释放 CPU 使用权,锁仍然占用;线程被放入超时等待队列,与
yield 相比,它会使线程较长时间得不到运行。
yield()方法仅释放 CPU 执行权,锁仍然占用,线程会被放入就绪队列,会在短时
间内再次执行。
wait 和 notify 必须配套使用,即必须使用同一把锁调用;
wait 和 notify 必须放在一个同步块中调用 wait 和 notify 的对象必须是他们所处
同步块的锁对象。

7 怎么唤醒阻塞线程?

notify() 方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有
用武之地。
而 notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。

8 创建线程的方式?

1、继承Thread类重写run方法
2、实现Runable中的run方法
3、实现Callable中的call方法

9 乐观锁的实现 10 分布式锁怎么解决锁过期? 11 redis怎么删除过期数据?

定时删除,定期删除,惰性删除默认,用到的时候才去检查key是否过期

12 线程池

线程池的构造方法
int corePoolSize,核心线程数
int maximumPoolSize,最大线程数
long keepAliveTime,超过最大线程数空闲时间
TimeUnit unit,时间单位
BlockingQueue workQueue 等待队列,双向FIFO
ThreadFactory threadFactory 创建线程的工厂
RejectedExecutionHandler handler拒绝策略
创建线程的工厂,以及拒绝策略可以自己指定,所以构造方法有四种。

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
13 线程池执行流程

14 四种任务拒绝策略

AbortPolicy:抛异常不执行新任务
DisCardPolicy:不抛任务不执行新任务
DisCardOldSetPolicy:移除队列最早的任务,加入新线程
CallerRunsPolicy:重新添加任务,调用execute

13 spring事务

REQUIRED
Spring默认的传播机制,如果外层有事务,则当前事务加入到外层事务,如果外层没有事务,新建一个事务执行
REQUES_NEW
如果外层有事务则挂起。如果外层没有事务,执行当前新开启的事务即可
SUPPORT
如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。
NOT_SUPPORT
以非事务运行,如果存在事务则挂起事务
NEVER
该传播机制不支持外层事务,即如果外层有事务就抛出异常
MANDATORY
与NEVER相反,如果外层没有事务,则抛出异常,必须以事务运行
NESTED
该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。

spring 14 数据库如何实现乐观锁与悲观锁,项目中怎么用的

乐观锁:加版本号
悲观锁:for update
如果for update 使用了索引就锁行,没有使用索引就锁表

15 数据库存储引擎的区别? 16 JMM线程模型 17 对JVM调优了解吗? 18 JVM区域划分? 19 方法区1.7与1.8实现的区别? 20 你对哪种设计模式用的最多?说一下怎么实现的 21 双亲委派机制知道吗? 22 springBoot使用多线程怎么使用? 23 你使用多线程会直接new Thread吗 24 线程池怎么使用的? 25 能指定的队列之间有什么区别吗?都在那种场景下使用 26 synchronized加锁的原理? 27 synchronized两个字节码指令怎么作用的? 28 说一下缓存的一致性? 29 volatile 怎么保证可见性?volatile为什么能保证可见性? 30FutureTask 有用过吗? 31 synchronized 与 ReentrantLock

synchronized 是java关键字,ReentrantLock是一个类
synchronized 无法判断锁的状态,ReentrantLock可以判断是否获取到锁
synchronized 会自动释放锁,ReentrantLock必须要手动释放锁!如果不释放锁,会造成死锁
synchronized 线程1(获得锁,阻塞),线程2会等待,ReentrantLock中线程不会一直等待,会尝试获取锁TrayLok()
synchronized 可重入锁,不可中断,非公平;ReentrantLock 可重入,可以判断锁,非公平(可以自己设置)
synchronized 适合锁少量的代码同步问题,ReentrantLock适合锁大量的同步代码

32 mysql调优 33 说一下分库分表? 34 mysql 的本地事务和分布式事务都有过吗? 35 本地事务使用的场景? 36 springboot使用本地事务?@Transcation 37 @Transcation中的参数有用过吗? 38 redis用的什么版本的?怎么选择的? 39 redis为什么使用单线程来处理业务?

面试官说还是为了最求极致的效率,多线程有额外的消耗,在单线程下保持高效率的话类似于时间片的分能。在很短的时间完成这个任务。

40 能说一下哨兵和集群的区别吗? 41 rabbitMq怎么保证消息的可靠性?

1、保证消息不丢失(三步)
1.1、开启事务(不推荐)
1.2、开启confirm(推荐)
1.3、开启RabbitMQ持久化(交换机、队列、消息)
1.4、关闭RabbitMQ自动ack(改成手动)
2、保证消息不重复消费
2.1、幂等性(每个消息用一个唯一标识来区分,消费前先判断标识有没有被消费过,若已消费过,则直接ACK)
3、RabbitMQ如何保证消息的顺序性
将消息放入同一个交换机,交给同一个队列,这个队列只有一个消费者,消费者只允许同时开启一个线程
4、RabbitMQ消息重试机制
消费者在消费消息的时候,如果消费者业务逻辑出现程序异常,这时候应该如何处理?
答案:使用消息重试机制(SpringBoot默认3次消息重试机制)

41 rabbitmq与roboimq,为什么会选择rabbitmq? 42 你们会把什么数据发送到kafka中? 43 你们的kafka有掉过消息吗? 44 常见的错误类型

ConcurrentModificationException:并发修改异常 在并发下集合类线程不安全
StackOverflowException 栈溢出异常

45 集合线程不安全怎么解决?

方案1:使用线程安全的集合Vector,但是这个集合内部直接使用synchronized保证线程安全,导致效率低。
方案2:使用集合类的顶层接口Collections的静态内部类
方案3:CopyonWrite 写入时复制,多个线程调用list的时候,读取是固定的,写入的时候存在覆盖的情况
在写入的避免覆盖,造成数据错误问题。
它完成了读写分离,提高效率。
CopyonWriteArrayList 比 Vector 效率高的地方,Vector所有的方法加了synchronized效率低,CopyonWriteArrayList 底层加的Lock锁的方式保证线程安全。

public class LlistTest {
    public static void main(String[] args) {
        ArrayList list1 = new ArrayList<>();
        Vector list2 = new Vector<>();//解决方案一
        List list = Collections.synchronizedList(new ArrayList<>());//解决方案二
        CopyOnWriteArrayList list3 = new CopyOnWriteArrayList<>();//解决方案三

        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}
46 redis怎么排序 48 JVM内存模型 49 rabitMQ怎么保证消息可靠性 50 sql慢查询 51 线程池阻塞队列有哪几种? 52 hashmap红黑树有什么弊端? 53 如果不想触发频繁fulljc怎么办?

可以通过调整MaxTenuringThreshold=15来限制对象添加老年代。

54 linkedBlockingQueue 与ArrayBlockingQueue的区别?

1.队列大小有所不同,ArrayBlockingQueue是有界的初始化必须指定大小,而linkedBlockingQueue可以是有界的也可以是无界的(Integer.MAX_VALUE),(而且不会初始化就占用一大片内存)对于后者而言,当添加速度大于移除速度时,在无界的情况下,可能会造成内存溢出等问题。
2.数据存储容器不同,ArrayBlockingQueue采用的是数组作为数据存储容器,而linkedBlockingQueue采用的则是以Node节点作为连接对象的链表。
3.两者的实现队列添加或移除的锁不一样,ArrayBlockingQueue实现的队列中的锁是没有分离的,即添加 *** 作和移除 *** 作采用的同一个ReenterLock锁,而linkedBlockingQueue实现的队列中的锁是分离的,其添加采用的是putLock,移除采用的则是takeLock,这样能大大提高队列的吞吐量,也意味着在高并发的情况下生产者和消费者可以并行地 *** 作队列中的数据,以此来提高整个队列的并发性能。

55 Redis是单线程的为什么还那么快?

1.redis是基于内存的,内存的读写速度非常快;
2.redis是单线程的,省去了很多上下文切换线程的时间;
3.redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。

56 如果不希望频繁触发FullGC?

可以通过调整to区到from区复制次数,来控制进入老年代的对象
可以通过调整MaxTenuringThreshold=15默认是15,可以调大

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/zaji/5638533.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存