Java基礎(chǔ)小知識(shí)點(diǎn)積累

對(duì)象一定分配在堆中嗎?有沒(méi)有了解逃逸分析技術(shù)?

  • 不一定的,JVM 通過(guò)「逃逸分析」 ,那些逃不出方法的對(duì)象會(huì)在棧上分配.
    逃逸分析是指分析指針動(dòng)態(tài)范圍的方法,它同編譯器優(yōu)化原理的指針?lè)治龊屯庑畏治鱿嚓P(guān)聯(lián)。當(dāng)
    變 量(或者對(duì)象)在方法中分配后,其指針有可能被返回或者被全局引用,這樣就會(huì)被其他方法
    或者 線(xiàn)程所引用,這種現(xiàn)象稱(chēng)作指針(或者引用)的逃逸(Escape)。通俗點(diǎn)講,如果一個(gè)對(duì)象
    的指針被 多個(gè)方法或者線(xiàn)程引用時(shí),那么我們就稱(chēng)這個(gè)對(duì)象的指針發(fā)生了逃逸。

volatile:可見(jiàn)性、順序性

保證并發(fā)編程的三要素(可見(jiàn)性、順序性、原子性)之二,可結(jié)合AtomicInteger等對(duì)象使用
volatile 本質(zhì)是在告訴 jvm 當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的,需要從主存中讀 取
使用 volatile 一般用于 狀態(tài)標(biāo)記量 和 單例模式的雙檢鎖。
1)保證了不同線(xiàn)程對(duì)這個(gè)變量進(jìn)行操作時(shí)的可見(jiàn)性,即一個(gè)線(xiàn)程修改了某個(gè)變量的值,這新值對(duì) 其他線(xiàn)程來(lái)說(shuō)是立即可見(jiàn)的,volatile 關(guān)鍵字會(huì)強(qiáng)制將修改的值立即寫(xiě)入主存。
2)禁止進(jìn)行指令重排序。

x = 2;//語(yǔ)句 1
y = 0;//語(yǔ)句 2
flag = true;//語(yǔ)句 3
x = 4;//語(yǔ)句 4
y = -1;//語(yǔ)句 5

由于flag 變量為 volatile 變量,那么在進(jìn)行指令重排序的過(guò)程的時(shí)候,不會(huì)將語(yǔ)句 3 放到語(yǔ)句 1、
語(yǔ)句 2 前面,也不會(huì)將語(yǔ)句 3 放到語(yǔ)句 4、語(yǔ)句 5 后面。但是要注意語(yǔ)句 1 和語(yǔ)句 2 的順序、語(yǔ)
句 4 和語(yǔ)句 5 的順序是不做任何保證的。

Thread中start()和run()區(qū)別

start()方法被用來(lái)啟動(dòng)新創(chuàng)建的線(xiàn)程,而且 start()內(nèi)部調(diào)用了 run()方法,這和直接調(diào)用 run()方法的 效果不一樣。當(dāng)你調(diào)用 run()方法的時(shí)候,只會(huì)是在原來(lái)的線(xiàn)程中調(diào)用,沒(méi)有新的線(xiàn)程啟動(dòng),start() 方法才會(huì)啟動(dòng)新線(xiàn)程。

Java對(duì)象創(chuàng)建過(guò)程

  1. 類(lèi)加載器將類(lèi)加載到內(nèi)存里
  2. 對(duì)類(lèi)的靜態(tài)變量、成員變量、靜態(tài)代碼塊進(jìn)行初始化
  3. 根據(jù)類(lèi)信息得知目標(biāo)對(duì)象大小,在堆內(nèi)存里分配空間
  • 內(nèi)存分配的方式一般有兩種,一種指針碰撞,另一種是空閑列表,JVM 會(huì)根據(jù) Java 堆內(nèi)存是否規(guī)整來(lái)決定內(nèi)存分配方式
  1. 目標(biāo)對(duì)象里的普通成員變量初始化為零值,int為0,對(duì)象為null
  2. 設(shè)置對(duì)象頭:如類(lèi)元信息、GC分代年齡、hashcode、鎖標(biāo)記等
  3. 執(zhí)行目標(biāo)對(duì)象內(nèi)部生成的 init 方法
  • init 方法是 Java 文件編譯之后在字節(jié)碼文件中生成的,它是一個(gè)實(shí)例構(gòu)造器,這個(gè)構(gòu)造器會(huì)把語(yǔ)句塊、變量初始化、調(diào)用父類(lèi)構(gòu)造器等操作組織在一起。

為什么ConcurrentHashMap的key、value不允許為null,而HashMap允許?

  1. 防止歧義:get(key)的時(shí)候返回null,不確定是key不存在,還是value=null
  2. HashMap可以使用containsKey(key)來(lái)判斷key是否存在,ConcurrentHashMap使用containsKey()后再使用get(key)不具有原子性,無(wú)法做出判斷

ThreadLocal會(huì)出現(xiàn)內(nèi)存泄漏嗎?

  • 回答:在使用不當(dāng)時(shí)會(huì)出現(xiàn)內(nèi)存泄露
    Thread的成員變量ThreadLocalMap的key是指向ThreadLocal對(duì)象的弱引用,代碼如下:
static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {

若ThreadLocal對(duì)象無(wú)其它強(qiáng)引用,那么可能會(huì)被GC,導(dǎo)致ThreadLocalMap的key為null,其對(duì)應(yīng)的value就無(wú)法被訪(fǎng)問(wèn),出現(xiàn)內(nèi)存泄露

  • 解決辦法:每次使用完 ThreadLocal 以后,主動(dòng)調(diào)用 remove()方法移除數(shù)據(jù)

創(chuàng)建線(xiàn)程池的辦法

  1. 使用Executors
  • newFixedThreadPool(int nThreads):創(chuàng)建一個(gè)固定大小的線(xiàn)程池。
  • newCachedThreadPool():創(chuàng)建一個(gè)可根據(jù)需要?jiǎng)?chuàng)建新線(xiàn)程的線(xiàn)程池。
  • newScheduledThreadPool(int corePoolSize):創(chuàng)建一個(gè)固定大小的線(xiàn)程池,可以執(zhí)行定時(shí)任務(wù)。
  • newSingleThreadExecutor():創(chuàng)建一個(gè)單線(xiàn)程的線(xiàn)程池。
  1. 使用 ThreadPoolExecutor 類(lèi)的構(gòu)造方法創(chuàng)建自定義線(xiàn)程池
最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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