知识小点

xiaoxiao2025-04-10  17

批量操作: jdbc批量 redis批量

用户表用redis哈希映射

线程,线程池, 设计模式, 集合,map基础 http 协议 tcp 协议 读写分离 dubbo负载非均衡

redis 限速: 短信验证码: 已手机号作为key,用redis exists判断key是否存在, 不存在,用redis setex 设置key 并且设置有效期, 存在,用redis incr(key) 自增,判断返回值是否大于指定值。

限制接口访问2秒只能访问一次: 判断key是否存在, 存在:返回请求频繁 不存在:setex key 2000 vlaue, 处理业务

多线程: 5中状态:

新建状态(new):线程刚创建, 就绪状态(runnable):线程对象调用start()方法,进入就绪状态,等待cpu调度。 运行状态(running):cpu开始调度就绪状态的线程时,此时线程才是真正执行。 阻塞状态(blocked):线程暂时放弃cpu执行权,线程停止执行:     阻塞分为3种:1等待阻塞:运行中的线程执行wait()方法,线程进入阻塞,会释放锁。              2,同步阻塞:线程在获取synchronized同步锁失败时,会进入同步阻塞状态              3,睡眠阻塞:线程执行sleep()进入阻塞状态,当sleep()状态超时时,线程进入就绪状态,注:sleep 不会释放锁。 死亡状态:线程执行完毕。

线程执行的过程中,遇到synchroneize修饰,会尝试去获取锁,获取不到,就等待,等待其他线程释放这个锁。

创建线程一般2种方式: 1,继承Thread类,重写Thread类的run()方法。 然后用start()启动线程。

2,实现Runnable 接口,重写Runnable 的run方法。 Runnable myRunnable =new MyRunnalbe(); new Thread (myRunnable ).start();

然后用start()启动线程。

然后Thread和Runnable的区别: Thread不适合资源共享,实现Runnable方式很容易实现资源共享

Runnable 接口比继承Thread所具有的优势: 1,适合多个相同的程序的线程去处理同一个资源。 2,可以避免java中的单继承的限制。 3,代码可以被多个线程共享 4,线程池只能放入实现Runnable类的线程。

join () :指当前线程等待子线程执行完成之后,当前线程才能往下面执行。 yield():线程礼让,指当前线程让出执行权,但还可能继续抢执行权。 sleep():当前线程进入等待状态,但不让出执行权。 wait():进入等待状态,会释放锁。

sleep()和wait()区别: 共同点:都表示线程进入等待状态,不会立刻往下执行。 不同点:sleep是Thread的方法。     wait和notify是obj方法,锁对象调用。

sleep必须捕获异常,wait不用。 sleep睡眠时,保持对象锁,仍然占有该锁。 wait睡眠时,释放对象锁。 sleep可以是任意位置, wait必须是在同步锁代码块里,并且是用锁对象调用。

volatile

在多线程中,多个消费者对共享资源消费,我一般都是借助redis阻塞队列完成 就比如: 1个生产者,用redis list集合 lpush方法,往list集合左边添加元素。 然后多个消费者,从list集合右边阻塞弹出元素,使用brpop()方法,谁抢到元素,谁就拿去消费。

线程池:ThreadPoolTaskExecutor

线程池作用: 主要是为了减少不必要的开销,因为线程的创建和销毁是开销巨大,耗费性能。

ThreadPool 实现原理:

1,ThreadPool extend ThreadGroup    ThreadPool 私有常量,是否关闭线程池。    ThreadPool 私有LinkedList<Runnable> workQueue 表示工作队列(任务队列)。

2,在ThreadPool 构造方法创建指定数量的线程,

public class ThreadPool extends ThreadGroup{          private LinkedList<Runnable> workQueue; //任务队列                public void ThreadPool(int poolSize){         workQueue =new ArrayList<Runnable>();         for(int i=0;i<poolSize;i++){             new WorkThread().start();         }     }

    //放任务进入任务队列准备执行     public void synchronized putTask(Runnable task){        workQueue.add(task);        notify();     }

    //从任务队列获取任务去执行     private Runnable synchronized getTask(){

            if(workQueue.size()==0){             wait();                      }         return workQueue.removeFirst();

    }

       private class WorkThread extends Thread{     @override     public void run(){         while(true){             //从任务列表里取出一个任务并执行             Runnbale task=getTask();             if(task!=null){                 task.run();             }         }              }          }

}

http协议面试题: http请求有三部分组成,分别是:请求行,消息报头,请求正文. http(超文本传输协议) 请求方法: get,post get与post: 1,get重点是从服务器获取资源,post重点是向服务器发送数据 2,get传输参数是拼接在请求url里的,用key=value形式,多个用&隔开,首个用?拼接,对用户是可见的。    post请求参数是放在请求实体,对用户是不可见的 3,get传输的数据量少,因为url有长度限制    post可以传输大量数据。 4,get是不安全的,可能会泄露私密信息,  post较get安全点

5,get传输中文会乱码,因为只支持ascll字符。 post可以正确传输中文。

http与https 1,http通信使用明文不加密,内容可能被窃听 1,http请求不验证通信方身份,数据可能会被篡改,

https就是http加上加密处理(sll)+认证+完整性保护

https过程: 1客户端使用https的url访问web服务器,与web服务器建立ssl连接。 2web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。 3客户端的浏览器与web服务器开始协商ssl连接的安全等级,也就是信息加密等级。 4客户端的浏览器根据双方同意的安全等级,建立会话秘钥,然后利用网站的公钥将会话秘钥加密,并传给网站。 5web服务器利用自己的私有解密出会话密码。 6web服务器利用会话秘钥加密与客户端之间的通信。

1,客户端请求https连接,返回证书、公钥 2,客户端产生随机(对称)秘钥 3,客户端使用公钥对对称加密秘钥加密,然后发给服务端 4,通过对称秘钥加密密文通信。

设计模式: 一,单例:

1,直接定义静态私有变量 =new Object();    在类初始化的时候就实例化对象

2,直接定义静态私有变量 =null; 然后在静态代码块里初始化对象。

3,调用getInstance获取对象时才初始化对象,

public static sychronized Object getInstance(){     if(instance==null){         instance =new Object();     }     return instance;

}

4,双重校验同步锁

public static object getInstance(){ if(obj==null){     synchronized(Singleton.class){

        if(obj==null){             obj=new Object();         }     }

}

return obj;

}

5,静态内部类 public class Singleto{     private static class SingletonHolder{         private static final Singleton instance =new Singleton(;)     }     private Singleton(){     }     public static final Singleton getInstance(){         return SingletonHolder.instance ;     }

}

这种是利用classloder的机制来保证初始化instance时只有一个线程。

二装饰模式: 可以在不改变代码的情况下,增加功能。容易暴露真实对象 public class newClass implements IClass{      private IClass target;//真实对象,被包装的对象      public newClass(IClass target){         this.target=target;     }          public void save(){         //其他业务         //调用目标对象         tartget.save();     }

}

三代理模式:      1):静态代理:缺点:一个代理类只能代理一种类型; 和装饰设计模式相比,静态代理没有暴漏真实对象,更安全;       2):动态代理: jvm通过反射机制动态生成的动态代理类,代理对象和真实对象在程序运行时才确定           小结: 动态代理需要为每一个去创建一个代理对象;             最小代理的单位是类;         如果只想一个类型中的某些方法,需要在invoke中对method方法进行判断即可;                 如果一个类实现了接口就用jdk动态代理;没有实现接口就用cglib动态代理;

               a):jdk动态代理:需要实现接口

四策略模式: redis 工具类书写时,用策略模式, 本地 用单机板redis shardJedist 线上用用集群板的redis rediscluster

五模板方法, 父类定义大家公共的逻辑 不同逻辑留给子类去实现

spring 读写分离 spring 提供一个动态数据源AbstractRoutingDataSource,子类需要继承它,并且实现它的一个方法, 在spring 需要数据源的时候会调用这个方法获取数据源。

spring xml 配置主、从数据源,动态数据源, 动态数据源 有一个map 属性,需要指向主,从数据源。

在事务管理器数据源指向动态数据源。

配置一个aop 前置通知,根据切入方法打上的标签来选择数据源,选择之后放在ThreadLocal 变量里,在spring需要数据源的时候 回掉子类方法,从threadLocal线程变量里获取指定的数据源。

集合: Vector 和ArrayList的关系: 1底层算法都基于数组 2ArrayList新的变长数组,Vector是ArrayList的前身 3Vector 相对于ArrayList来说,线程更安全,但是性能较低

Stack栈:

底层是数组,特点:先进后出

push:压入栈顶 peek:弹出栈顶,不移除元素 pop:弹出栈顶,移除元素

集合:list queue set

list:ArrayList Vector LinkedList 

list:记录添加顺序,元素可重复 ArrayList、Vector :底层是数组, LinkedList:底层是双向链表,会记录头和尾部

queue 底层是队列,先进先出

Set接口:不会记录添加顺序,元素不可以重复 set是通过equal() 和hashcode 保证唯一的

Dueue 双向队列

HashSet类:底层是哈希表算法 LinkedHashSet 类:双向链表和哈希表算法 LinkedhashSet 是hashset的子类 哈希表算法决定存储位置。 双向链表算法:决定输出顺序。

LinkedhashSet相对于hashset来说性能更低,因为要保证输出顺序。 LinkedhashSet 不仅可以保证添加顺序,还可以保证元素不能重复。

TreeSet :底层平衡二叉树 对象集合必须是同一种类型,不然会报错。

map 所有键值对:map.entrySet(); 所有键 :map.keySet() 所有值:values();

map 遍历: Map<Interger,Integer> map =new HashMap<Integer,Integer>(); for(Integer key:map.keySet()){     map.get(key);

}

for(Entry<Integer,Integer> entry:map.entrySet()){     entry.getKey();     entry.getValue();

}

Iterator<Integer> itegerto =map.keySet().iterator(); while(iterator.hasNext()){   map.get(key);

}

hashmap :线程不安全,方法不是同步的  , 允许有null的键和值,效率高一点,  HashMap继承自AbstractMap类 hastable :线程安全, 方法是同步的,     不允许有null键和值,效率稍低,  Hashtable继承自Dictionary类

HashMap底层是一个Entry数组,当发生hash冲突的时候,hashmap是采用链表的方式来解决的, 在对应的数组位置存放链表的头结点。对链表而言,新加入的节点会从头结点加入。

Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。

排序: 冒泡排序:   /**      * 冒泡排序      * 比较相邻的元素。如果第一个比第二个大,就交换他们两个。        * 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。        * 针对所有的元素重复以上的步骤,除了最后一个。      * 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。       * @param numbers 需要排序的整型数组      */     public static void bubbleSort(int[] numbers)     {         int temp = 0;         int size = numbers.length;         for(int i = 0 ; i < size-1; i ++)         {         for(int j = 0 ;j < size-1-i ; j++)         {             if(numbers[j] > numbers[j+1])  //交换两数位置             {             temp = numbers[j];             numbers[j] = numbers[j+1];             numbers[j+1] = temp;             }         }         }     }

选择排序: /**      * 选择排序算法      * 在未排序序列中找到最小元素,存放到排序序列的起始位置        * 再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。       * 以此类推,直到所有元素均排序完毕。       * @param numbers      */     public static void selectSort(int[] numbers)     {     int size = numbers.length; //数组长度     int temp = 0 ; //中间变量          for(int i = 0 ; i < size ; i++)     {         int k = i;   //待确定的位置         //选择出应该在第i个位置的数         for(int j = size -1 ; j > i ; j--)         {         if(numbers[j] < numbers[k])         {             k = j;         }         }         //交换两个数         temp = numbers[i];         numbers[i] = numbers[k];         numbers[k] = temp;     }     }

直播,有聊共同好友,抢红包, springmvc 流程, 自我介绍 复习一遍txt

直播在线人数: 

直播开启直播时会创建一个消息队列频道,用户进直播时就订阅这个频道,接收消息。

用户进入直播 的时候,通过websoket连接服务器: 要做的事情: 1,以用户的会话id+直播id为消息队列名字,订阅一个该直播的消息队列频道。 2,用redis 计数器 incrby  计数这个直播在线人数加1. 3,通过用户会话id 找出该用户登录信息(redist),把用户id存进redis在线用户列表set集合里(sadd())。 4,往该直播消息队列频道发一条消息:目前最新的在线人数,其他用户收到订阅消息就通过websoket发给前端。

用户退出直播(websoket断开): 1,直播计数器 redis  decrby 减1, 2, 直播在线用户列表 redis set 集合剔除该用户id srem(); 3,往这个直播消息队列频道发一条消息,当前最新的在线人数,客户端收到就更新在线人数。

有聊共同好友: 用户关系表 friends

userId: friendid:

已知条件是我的id,你的id

select * from friends f1 ,friends f2  where f1.userid=myuserid and f2.userid=youid and f1.friendid=f2.friendid

聊天群组抢红包: 红包发起: 红包发起的时候前端传给我的数据是:一个红包金额,红包数量,拆分规则:红包金额是否随机。 然后我就把这个红包当做一个大红包保存到数据库,就有一个大红包id。 把这个大红包id 缓存到redis 中, 大红包id作为key 有效时间24小时。 然后把这个这个大红包按照红包拆分规则 拆成一个个小的红包,保存到数据库里面。 然后把这些小红包id 保存到redis set 集合里。 然后往群组发一条红包消息。

红包领取: 1,首先判断这个大红包是否过去,用redist exist 判断key是否存在,如果存在那说明没过期,不存在过期了。

2,如果没过期的话,再判断这个用户是否重复抢这个红包,用redis setnx分布式锁机制,大红包id+用户id作为key,key有效时间大于大红包的有效时间。 如果setnx 成功那说明他没抢, 3,没抢的话,就从小红包列表 set 集合 spop随机弹出一个红包,把用户id和小红包id进行绑定。

事务隔离级别: 1,读未提交:别人事务还没提交,我就可以读取到。 2,不可重复读:同一个事务中,前后两次读取到的数据不一样。 3,可重复读:同一个事务中,前后两次读取到的数据一样。 4   串行化:事务排队

jvm 栈,堆,静态区

堆: 1,new 出来的对象存在堆区,堆区不存放基本数据类型和对象引用,只存放对象本身。 2,jvm 只有一个堆区,堆区被所有线程共享。 3,运行时动态分配内存,存取速度慢,内存数据由java垃圾收集器自动回收。

栈: 1,每个线程包含一个栈区,栈区只保存基本数据类型和对象的引用。 2,每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。 3,栈存取速度比堆快,

方法区: 1又叫静态区,跟堆一样,被所有线程共享,方法区包含所有的class和static变量。 2方法区中包含的都是整个程序中永远唯一的元素,如class,static 变量。

 

 

spring mvc 流程 1,用户发送请求到前端控制器DispatcherServlet. 2,DispatcherServlet收到请求调用HandlerMapping处理器映射器。 3,处理器映射器找到具体的处理器(可以根据xml,注解进行查找),生成处理器对象及如果有拦截器的话也一起生成,然后返回给dispatcherServlet 4,dispatcherservlet 调用handlerAdapter 处理适配器。 5,HandlerAdapter经过适配之后调用具体的后端控制器,就是后端的controller, 6,controller执行完成之后返回modelAndview 给handlerAdapter适配器。 7,handlerAdapter适配器就将controller执行结果modelAndview返回给dispatcherservlet 8,dispatcherServlet将modelAndview 传给viewRelover视图解析器。 9,viewReslove解析后返回具体view给dispatcherServlet 10,dispatcherServlet根据view渲染视图,相应给用户。

MySQL in

select * from table1 pc where pc.account_id in (45); select * from table1 pc where (pc.account_id) in ((45)); select * from table1 pc where (pc.account_id,pc.app_id) in ((45,'in123456789'));

转载请注明原文地址: https://www.6miu.com/read-5027961.html

最新回复(0)