知識小點

批量操作:
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渲染視圖,相應給用戶。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章