Java-1

  1. 容器基本內(nèi)容
  2. HashMap的底層
  3. 多線程同步方法
  4. 消息隊(duì)列問(wèn)題
  5. 設(shè)計(jì)模式中的生產(chǎn)者消費(fèi)者模型
  6. 同步異步接口
  7. Mysql兩種引擎的區(qū)別
  8. mybatis與hibernate的區(qū)別
  9. Struts2 攔截器與Spring AOP的區(qū)別
  10. HashMap容量為什么是2^n
  11. HashMap的負(fù)載因子

1. 容器基本內(nèi)容

Java集合類里面最基本的接口如下:

Collection:一個(gè)獨(dú)立元素的序列,這些元素都服從一條或者多條規(guī)則。 List必須按照插入的順序保存元素,而set不能有重復(fù)的元素。Queue按照排隊(duì)規(guī)則來(lái)確定對(duì)象產(chǎn)生的順序(通常與它們被插入的順序相同)。

Map:一組成對(duì)的“鍵值對(duì)”對(duì)象,允許你使用鍵來(lái)查找值。

2. HashMap的底層

HashMap是基于哈希表的Map接口的非同步實(shí)現(xiàn),Java最基本數(shù)據(jù)結(jié)構(gòu)就是兩種,一種是數(shù)組,一種是引用。所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個(gè)基本結(jié)構(gòu)來(lái)構(gòu)造的,HashMap也不例外。
HashMap實(shí)際上是一個(gè)“鏈表散列”的數(shù)據(jù)結(jié)構(gòu),即數(shù)組和鏈表的結(jié)合體。HashMap底層就是一個(gè)數(shù)組結(jié)構(gòu),數(shù)組中的每一項(xiàng)又是一個(gè)鏈表。當(dāng)新建一個(gè)HashMap的時(shí)候,就會(huì)初始化一個(gè)數(shù)組。Entry就是數(shù)組中的元素,每個(gè) Map.Entry 其實(shí)就是一個(gè)key-value對(duì),它持有一個(gè)指向下一個(gè)元素的引用,這就構(gòu)成了鏈表。

3. 多線程同步方法

  • 為何要使用同步?
    java允許多線程并發(fā)控制,當(dāng)多個(gè)線程同時(shí)操作一個(gè)可共享的資源變量時(shí)(如數(shù)據(jù)的增刪改查), 將會(huì)導(dǎo)致數(shù)據(jù)不準(zhǔn)確,相互之間產(chǎn)生沖突,因此加入同步鎖以避免在該線程沒有完成操作之前,被其他線程的調(diào)用, 從而保證了該變量的唯一性和準(zhǔn)確性。

  • 1.同步方法
    即有synchronized關(guān)鍵字修飾的方法。
    由于java的每個(gè)對(duì)象都有一個(gè)內(nèi)置鎖,當(dāng)用此關(guān)鍵字修飾方法時(shí), 內(nèi)置鎖會(huì)保護(hù)整個(gè)方法。在調(diào)用該方法前,需要獲得內(nèi)置鎖,否則就處于阻塞狀態(tài)。

 public synchronized void save(){
}

注: synchronized關(guān)鍵字也可以修飾靜態(tài)方法,此時(shí)如果調(diào)用該靜態(tài)方法,將會(huì)鎖住整個(gè)類

    1. 同步代碼塊
      即有synchronized關(guān)鍵字修飾的語(yǔ)句塊。 被該關(guān)鍵字修飾的語(yǔ)句塊會(huì)自動(dòng)被加上內(nèi)置鎖,從而實(shí)現(xiàn)同步。
synchronized(object){ 
}
  • 3.使用特殊域變量(volatile)實(shí)現(xiàn)線程同步
    volatile關(guān)鍵字為域變量的訪問(wèn)提供了一種免鎖機(jī)制, 使用volatile修飾域相當(dāng)于告訴虛擬機(jī)該域可能會(huì)被其他線程更新, 因此每次使用該域就要重新計(jì)算,而不是使用寄存器中的值 volatile不會(huì)提供任何原子操作,它也不能用來(lái)修飾final類型的變量。
//需要同步的變量加上volatile
private volatile int account = 100;
    1. 使用重入鎖
      ReenreantLock類的常用方法有:
      ReentrantLock() : 創(chuàng)建一個(gè)ReentrantLock實(shí)例
      lock() : 獲得鎖
      unlock() : 釋放鎖
//需要聲明這個(gè)鎖
private Lock lock = new ReentrantLock();
lock.lock();
try{
      account += money;
}finally{
      lock.unlock();
 }
  • 5.使用局部變量實(shí)現(xiàn)線程同步
    如果使用ThreadLocal管理變量,則每一個(gè)使用該變量的線程都獲得該變量的副本,
    副本之間相互獨(dú)立,這樣每一個(gè)線程都可以隨意修改自己的變量副本,而不會(huì)對(duì)其他線程產(chǎn)生影響。
    ThreadLocal 類的常用方法
    ThreadLocal() : 創(chuàng)建一個(gè)線程本地變量
    get() : 返回此線程局部變量的當(dāng)前線程副本中的值
    initialValue() : 返回此線程局部變量的當(dāng)前線程的"初始值"
    set(T value) : 將此線程局部變量的當(dāng)前線程副本中的值設(shè)置為value
        public class Bank{
            //使用ThreadLocal類管理共享變量account
            private static ThreadLocal<Integer> account = new ThreadLocal<Integer>(){
                @Override
                protected Integer initialValue(){
                    return 100;
                }
            };
            public void save(int money){
                account.set(account.get()+money);
            }
            public int getAccount(){
                return account.get();
            }
        }

上面的五種偏底層

  • 6.使用原子變量實(shí)現(xiàn)線程同步

原子操作就是指將讀取變量值、修改變量值、保存變量值看成一個(gè)整體來(lái)操作即-這幾種行為要么同時(shí)完成,要么都不完成。
在java的util.concurrent.atomic包中提供了創(chuàng)建了原子類型變量的工具類

class Bank {
        private AtomicInteger account = new AtomicInteger(100);

        public AtomicInteger getAccount() {
            return account;
        }

        public void save(int money) {
            account.addAndGet(money);
        }
    }
  • 7.使用阻塞隊(duì)列實(shí)現(xiàn)線程同步
    阻塞隊(duì)列與普通隊(duì)列的區(qū)別在于,當(dāng)隊(duì)列是空的時(shí),從隊(duì)列中獲取元素的操作將會(huì)被阻塞,或者當(dāng)隊(duì)列是滿時(shí),往隊(duì)列里添加元素的操作會(huì)被阻塞。
    同時(shí),阻塞隊(duì)列里面的put、take方法是被加:synchronized 同步限制。

4. 消息隊(duì)列問(wèn)題

消息隊(duì)列在實(shí)際應(yīng)用中常用的使用場(chǎng)景。異步處理,應(yīng)用解耦,流量削鋒和消息通訊四個(gè)場(chǎng)景。

    1. 異步處理
      引入消息隊(duì)列,將不是必須的業(yè)務(wù)邏輯,異步處理。
    1. 應(yīng)用解耦
      場(chǎng)景說(shuō)明:用戶下單后,訂單系統(tǒng)需要通知庫(kù)存系統(tǒng)。傳統(tǒng)的做法是,訂單系統(tǒng)調(diào)用庫(kù)存系統(tǒng)的接口。假如庫(kù)存系統(tǒng)無(wú)法訪問(wèn),則訂單減庫(kù)存將失敗,從而導(dǎo)致訂單失敗??梢酝ㄟ^(guò)消息隊(duì)列將兩者解耦和。
    1. 流量削鋒
      流量削鋒也是消息隊(duì)列中的常用場(chǎng)景,一般在秒殺或團(tuán)搶活動(dòng)中使用廣泛。
      場(chǎng)景說(shuō)明:秒殺活動(dòng),一般會(huì)因?yàn)榱髁窟^(guò)大,導(dǎo)致流量暴增,應(yīng)用掛掉。為解決這個(gè)問(wèn)題,一般需要在應(yīng)用前端加入消息隊(duì)列。
    1. 日志處理
      日志處理是指將消息隊(duì)列用在日志處理中,比如Kafka的應(yīng)用,解決大量日志傳輸?shù)膯?wèn)題。

5. 設(shè)計(jì)模式中的生產(chǎn)者消費(fèi)者模型:

生產(chǎn)者消費(fèi)者問(wèn)題是線程模型中的經(jīng)典問(wèn)題:生產(chǎn)者和消費(fèi)者在同一時(shí)間段內(nèi)共用同一存儲(chǔ)空間,生產(chǎn)者向空間里生產(chǎn)數(shù)據(jù),而消費(fèi)者取走數(shù)據(jù)。

生產(chǎn)者消費(fèi)者模式是通過(guò)一個(gè)容器來(lái)解決生產(chǎn)者和消費(fèi)者的強(qiáng)耦合問(wèn)題。生產(chǎn)者和消費(fèi)者彼此之間不直接通訊,而通過(guò)阻塞隊(duì)列來(lái)進(jìn)行通訊,所以生產(chǎn)者生產(chǎn)完數(shù)據(jù)之后不用等待消費(fèi)者處理,直接扔給阻塞隊(duì)列,消費(fèi)者不找生產(chǎn)者要數(shù)據(jù),而是直接從阻塞隊(duì)列里取,阻塞隊(duì)列就相當(dāng)于一個(gè)緩沖區(qū),平衡了生產(chǎn)者和消費(fèi)者的處理能力。

這個(gè)阻塞隊(duì)列就是用來(lái)給生產(chǎn)者和消費(fèi)者解耦的。

6. 同步異步接口:

同步交互:指發(fā)送一個(gè)請(qǐng)求,需要等待返回,然后才能夠發(fā)送下一個(gè)請(qǐng)求,有個(gè)等待過(guò)程;
異步交互:指發(fā)送一個(gè)請(qǐng)求,不需要等待返回,隨時(shí)可以再發(fā)送下一個(gè)請(qǐng)求,即不需要等待。

7. Mysql兩種引擎的區(qū)別:

主要區(qū)別:
MYIASM為默認(rèn)引擎。
1、MyIASM是非事務(wù)安全的,而InnoDB是事務(wù)安全的
2、MyIASM鎖的粒度是表級(jí)的,而InnoDB支持行級(jí)鎖
3、MyIASM支持全文類型索引,而InnoDB不支持全文索引
4、MyIASM相對(duì)簡(jiǎn)單,效率上要優(yōu)于InnoDB,小型應(yīng)用可以考慮使用MyIASM
5、MyIASM表保存成文件形式,跨平臺(tái)使用更加方便

8. mybatis與hibernate的區(qū)別

  • Mybatis學(xué)習(xí)門檻低,簡(jiǎn)單易學(xué),程序員直接編寫原生態(tài)sql,可嚴(yán)格控制sql執(zhí)行性能,靈活度高,非常適合對(duì)關(guān)系數(shù)據(jù)模型要求不高的軟件開發(fā)

  • Hibernate對(duì)象/關(guān)系映射能力強(qiáng),數(shù)據(jù)庫(kù)無(wú)關(guān)性好,對(duì)于關(guān)系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開發(fā)可以節(jié)省很多代碼,提高效率。但是Hibernate的學(xué)習(xí)門檻高。

9. Struts2 攔截器與Spring AOP的區(qū)別

  • Struts2 簡(jiǎn)單來(lái)說(shuō),就是一個(gè)攔截器棧也就是一系列的攔截器。處理用戶的請(qǐng)求,OGNL的使用,表單驗(yàn)證等都是默認(rèn)的攔截器在起作用。

  • AOP,面向切面編程,考慮對(duì)哪些方法進(jìn)行攔截,攔截后怎么處理,這些關(guān)注點(diǎn)稱之為橫切關(guān)注點(diǎn)。所以spring的攔截器,主要體現(xiàn)在AOP的事務(wù)管理方面,還有比如一些錯(cuò)誤或者異常的日志的顯示也是通過(guò)配置spring的log攔截器來(lái)實(shí)現(xiàn)的。

廣義來(lái)說(shuō)spring和struts2的攔截器的工作原理都一樣。

10. HashMap的容量為什么是2^n?

static int indexFor(int h,int length) {
        return h & (length-1);
    }

key的hashCode經(jīng)過(guò)hash后,為了讓其在table(table為hashMap的entry[])的范圍內(nèi),需要再hash一次。這里實(shí)際上是采用的“除余法”。

如果length是2的N次方,那么數(shù)h對(duì)length的模運(yùn)算結(jié)果等價(jià)于a和(length-1)的按位與運(yùn)算,也就是 h%length <=> h&(length-1)。
位運(yùn)算當(dāng)然比取余效率高,所以HashMap容量要求為2^n。

11. HashMap的負(fù)載因子

負(fù)載因子默認(rèn)是0.75,會(huì)影響HashMap的性能。

threshold = (int)(capacity * loadFactor);
threshold為HashMap的size最大值

所以負(fù)載因子越大則散列表的裝填程度越高,也就是能容納更多的元素,元素多了,鏈表就長(zhǎng)了,所以此時(shí)索引效率就會(huì)降低。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文是我自己在秋招復(fù)習(xí)時(shí)的讀書筆記,整理的知識(shí)點(diǎn),也是為了防止忘記,尊重勞動(dòng)成果,轉(zhuǎn)載注明出處哦!如果你也喜歡,那...
    波波波先森閱讀 11,589評(píng)論 4 56
  • Java繼承關(guān)系初始化順序 父類的靜態(tài)變量-->父類的靜態(tài)代碼塊-->子類的靜態(tài)變量-->子類的靜態(tài)代碼快-->父...
    第六象限閱讀 2,246評(píng)論 0 9
  • 在一個(gè)方法內(nèi)部定義的變量都存儲(chǔ)在棧中,當(dāng)這個(gè)函數(shù)運(yùn)行結(jié)束后,其對(duì)應(yīng)的棧就會(huì)被回收,此時(shí),在其方法體中定義的變量將不...
    Y了個(gè)J閱讀 4,547評(píng)論 1 14
  • 舞清風(fēng)_f327閱讀 89評(píng)論 0 0
  • 七月盡了,八月新生。 八月是帶著濕漉漉的水氣來(lái)的。清晨就有雨,呼呼啦啦在窗前,草葉子上總也不干,分不清是露,是雨,...
    月光墨墨閱讀 262評(píng)論 0 0

友情鏈接更多精彩內(nèi)容