日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

arraylist线程安全吗_Java的线程安全、单例模式、JVM内存结构等知识梳理

發(fā)布時間:2024/7/23 java 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 arraylist线程安全吗_Java的线程安全、单例模式、JVM内存结构等知识梳理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

java技術(shù)總結(jié)

知其然,不知其所以然 !在技術(shù)的海洋里,遨游!

做一個積極的人

編碼、改bug、提升自己

我有一個樂園,面向編程,春暖花開!


本篇以一些問題開頭,請先不看答案,自己思考一下,看一下你能回答上來多少! 本文內(nèi)容較多,可以收藏后查看!

思考一下

1、都說String是不可變的,為什么我可以這樣做呢? String a = "1"; a = "2";

2、HashMap的實現(xiàn)原理 ?

3、寫出三種單例模式,如果能考慮線程安全最好?

4、ArrayList和LinkedList有什么區(qū)別 ?

5、什么是線程安全,為什么會出現(xiàn)線程安全問題?

6、實現(xiàn)線程的二種方式?

7、Lock與Synchronized的區(qū)別?

8、JVM的內(nèi)存結(jié)構(gòu) ?

9、請解釋如下jvm參數(shù)的含義:

-server -Xms512m -Xmx512m -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m -XX:MaxTenuringThreshold=20 -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly

10、數(shù)據(jù)庫隔離級別有哪些,各自的含義是什么,MYSQL默認的隔離級別是是什么?


1、都說String是不可變的,為什么我可以這樣做呢,String a = "1";a = "2";

先看一段代碼,然后通過代碼和一幅圖進行講解!

public class StringTest { public static void main(String[] args) { String s = "ABCabc"; System.out.println("s1.hashCode() = " + s.hashCode() + "--" + s); s = "123456"; System.out.println("s2.hashCode() = " + s.hashCode() + "--" + s); //運行后輸出的結(jié)果不同,兩個值的hascode也不一致, //說明設(shè)置的值在內(nèi)存中存儲在不同的位置 }}

【首先創(chuàng)建一個String對象s,然后讓s的值為“ABCabc”, 然后又讓s的值為“123456”。 從打印結(jié)果可以看出,s的值確實改變了。那么怎么還說String對象是不可變的呢?

其實這里存在一個誤區(qū): s只是一個String對象的引用,并不是對象本身。對象在內(nèi)存中是一塊內(nèi)存區(qū),成員變量越多,這塊內(nèi)存區(qū)占的空間越大。引用只是一個4字節(jié)的數(shù)據(jù),里面存放了它所指向的對象的地址,通過這個地址可以訪問對象。

也就是說,s只是一個引用,它指向了一個具體的對象,當s=“123456”; 這句代碼執(zhí)行過之后,又創(chuàng)建了一個新的對象“123456”, 而引用s重新指向了這個心的對象,原來的對象“ABCabc”還在內(nèi)存中存在,并沒有改變。內(nèi)存結(jié)構(gòu)如下圖所示:

---圖片摘自【Java中的String為什么是不可變的? -- String源碼分析】

  • 相關(guān)參考文章

1:【知乎-胖胖 回答】如何理解 String 類型值的不可變?: https://www.zhihu.com/question/20618891

2:8 張圖理解 Java :https://mp.weixin.qq.com/s/nidDtGZ9P-YJaXSxvZPv_w

一圖講解String


2、HashMap的實現(xiàn)原理

HashMap 我之前的專欄中也有寫過,分析HashMap要注意JDK版本,jdk1.7和jdk1.8中底層的實現(xiàn)就有不同。

說簡單點HashMap是一個集合,通過put(key,value)存儲數(shù)據(jù),然后使用get(key)獲取數(shù)據(jù)。

實現(xiàn)原理是基于hashing原理,使用hash算法實現(xiàn)。 jdk1.7 數(shù)組+鏈表 jdk1.8 數(shù)組+鏈表+紅黑樹

  • 詳情可參考下面博文:
  • java集合系列——Map之HashMap介紹(八): http://blog.csdn.net/u010648555/article/details/60324303 HashMap的工作原理 : http://www.importnew.com/7099.html Java8系列之重新認識HashMap : http://www.importnew.com/20386.html

3、寫出三種單例模式,如果能考慮線程安全最好

首先總結(jié)目前實現(xiàn)單例模式的方式有以下五種:

  • 餓漢式,線程安全
  • 懶漢式,線程不安全(注意加synchronized,變線程安全)
  • 雙重檢驗鎖(注意將instance 變量聲明成 volatile,并注意jdk版本大于等于1.5)
  • 靜態(tài)內(nèi)部類 ,線程安全
  • 枚舉,線程安全

注:推薦使用后面三種

具體代碼就不一一寫了:如果想了解具體的代碼如何寫,點擊下面:

你真的會寫單例模式嗎——Java實現(xiàn): http://www.importnew.com/18872.html

  • 雙重檢驗鎖 : jdk1.5以后才能正確工作
public class Singleton { private static volatile Singleton singleton = null; private Singleton(){} public static Singleton getSingleton(){ if(singleton == null){ synchronized (Singleton.class){ if(singleton == null){ singleton = new Singleton(); } } } return singleton; } }
  • 靜態(tài)內(nèi)部類 : 延時加載,線程安裝
public class Singleton { private static class Holder { private static Singleton singleton = new Singleton(); } private Singleton(){} public static Singleton getSingleton(){ return Holder.singleton; }}
  • 枚舉 : [Effective Java] 推薦盡可能地使用枚舉來實現(xiàn)單例
public enum Singleton { INSTANCE; private String name; public String getName(){ return name; } public void setName(String name){ this.name = name; }}

4 、ArrayList和LinkedList有什么區(qū)別

我之前博客也有寫過 , java集合系列——List集合總結(jié) :http://blog.csdn.net/u010648555/article/details/59708627

這里在說明一下: 簡單介紹 1 ArrayList是基于數(shù)組實現(xiàn)的,是一個數(shù)組隊列。可以動態(tài)的增加容量!

  • LinkedList是基于鏈表實現(xiàn)的,是一個雙向循環(huán)列表。可以被當做堆棧使用!
  • 使用場景

  • 當集合中對插入元素數(shù)據(jù)的速度要求不高,但是要求快速訪問元素數(shù)據(jù),則使用ArrayList!
  • 當集合中對訪問元素數(shù)據(jù)速度不做要求不高,但是對插入和刪除元素數(shù)據(jù)速度要求高的情況,則使用LinkedList!
  • 具體分析 1.ArrayList隨機讀取的時候采用的是get(index),根據(jù)指定位置讀取元素,而LinkedList則采用size/2 ,二分法去加速一次讀取元素,效率低于ArrayList! 2.ArrayList插入時候要判斷容量,刪除時候要將數(shù)組移位,有一個復制操作,效率低于LinkList!而LinkedList直接插入,不用判斷容量,刪除的時候也是直接刪除跳轉(zhuǎn)指針節(jié)點,沒有復制的操作!


    5、什么是線程安全,為什么會出現(xiàn)線程安全問題?

    【參考書 :Java并發(fā)編程實戰(zhàn)】:https://book.douban.com/subject/10484692/

    線程安全就是多線程訪問時,采用了加鎖機制,當一個線程訪問該類的某個數(shù)據(jù)時,進行保護,其他線程不能進行訪問直到該線程讀取完,其他線程才可使用。不會出現(xiàn)數(shù)據(jù)不一致或者數(shù)據(jù)污染。[百度百科:線程安全]

    線程安全 = 線程(多個線程) + 數(shù)據(jù)一致!

    思考1:為什么會出現(xiàn)線程安全問題?

    從百度百科的概念可以知道,發(fā)送線程安全問題的兩個條件:

    • 多線程訪問
    • 訪問某個數(shù)據(jù),(這里強調(diào)一下,某個數(shù)據(jù)是實例變量即對線程是共享的)
    • 這兩個條件都必須滿足,缺一不可,否則不會出現(xiàn)線程安全問題。

    思考2:怎么解決線程安全問題?

    通過加鎖機制,可以使用關(guān)鍵字synchronized,或者java并發(fā)包中的Lock。還有在使用集合中的類如ArrayList或者HashMap時要考慮是否存在線程安全問題,如果存在最好使用ConcurrentHashMap替代hashMap,或者使用Collections.synchronizedXXX進行封裝!

    • 實例:通過一段代碼演示線程安全和非線程安全
    /** * 線程安全和線程不安全---簡單實例 * * @author:dufy * @version:1.0.0 * @date 2017/10/13 */public class ThreadSafey { private int countUnSafe = 0;//實例變量 private int countSafe = 0; //線程不安全的方法 public void addUnSafe(){ try { Thread.sleep(100);//為了更好的測試。休眠100ms } catch (InterruptedException e) { e.printStackTrace(); } countUnSafe ++; System.out.println("countUnSafe = " + countUnSafe); } //線程安全的方法 //這里也可以使用使用同步代碼塊的方式,建議在實際開發(fā)使用同步代碼塊,相對比同步方法好很多, 也可以使用Lock進行加鎖! public synchronized void addSafe(){ try { Thread.sleep(100);//為了更好的測試。休眠100ms } catch (InterruptedException e) { e.printStackTrace(); } countSafe ++; System.out.println("countSafe = " + countSafe); } public static void main(String[] args) { ThreadSafey ts = new ThreadSafey(); UnSafeT unSafeT = new UnSafeT(ts); SafeT safeT = new SafeT(ts); //啟動10個線程 for (int i = 0; i < 10; i++) { Thread thread = new Thread(unSafeT); thread.start(); } //啟動10個線程 for (int i = 0; i < 10; i++) { Thread thread = new Thread(safeT); thread.start(); } }}//不安全線程測試類class UnSafeT implements Runnable{ private ThreadSafey threadSafey; public UnSafeT(ThreadSafey threadSafey){ this.threadSafey = threadSafey; } @Override public void run() { threadSafey.addUnSafe(); }}//安全線程測試類class SafeT implements Runnable{ private ThreadSafey threadSafey; public SafeT(ThreadSafey threadSafey){ this.threadSafey = threadSafey; } @Override public void run() { threadSafey.addSafe(); }}

    運行結(jié)果如下,多次運行后,發(fā)現(xiàn)countUnSafe總是有重復的值,并且不按照順序輸出,最后的結(jié)果也不是10; countSafe 按照順序打印,最后的結(jié)果也是10。如果你運行了上面的代碼,可能和我執(zhí)行下面打印的不一樣,但是結(jié)論是一樣的。

    countUnSafe = 3countUnSafe = 3countUnSafe = 3countUnSafe = 3countUnSafe = 3countUnSafe = 5countUnSafe = 8countUnSafe = 8countUnSafe = 6countUnSafe = 5countSafe = 1countSafe = 2countSafe = 3countSafe = 4countSafe = 5countSafe = 6countSafe = 7countSafe = 8countSafe = 9countSafe = 10

    線程安全說簡單了就上面這些內(nèi)容,如何深入需要知道線程的工作原理,JVM下線程是如何進行工作,為什么實例變量會存在線程安全問題,而私有變量不會出現(xiàn),這就和變量在內(nèi)存中創(chuàng)建和存儲的位置有關(guān)。下面進行簡單的說明,不會一一展開了。

    在程序運行后JVM中有一個主內(nèi)存,線程在創(chuàng)建后也會有一個自己的內(nèi)存(工作內(nèi)存),會拷貝主內(nèi)存的一些數(shù)據(jù),每個線程之間能夠共享主內(nèi)存,而不能訪問其他線程的工作內(nèi)存,那么一個變量是實例變量的時候,如果沒有加鎖機制,就會出現(xiàn)線程安全問題。

    比如:系統(tǒng)有線程A和線程B,這兩個線程同時訪問了addUnSafe方法,并將countUnsafe變量拷貝在自己的內(nèi)存中(countUnsafe = 0),然后進行操作,那么這兩個線程 都執(zhí)行countUnsafe++,這兩個線程的工作內(nèi)存中countUnsafe = 1;然后寫回主內(nèi)存,此時主內(nèi)存countUnsafe = 1,當另一個線程C訪問時候,C工作內(nèi)存操作的countUnsafe的值就是1,此時發(fā)生了線程安全問題。

    【圖片來自--java并發(fā)編程藝術(shù)-第二章 java內(nèi)存模型抽象結(jié)構(gòu)】

    JMM模型

    先就講這么多了,這些在面試中是有定的深度了。后面有時間專門在深入總結(jié)。


    6、實現(xiàn)線程的二種方式

    Java中有兩種方式實現(xiàn)多線程,一種是繼承Thread類,一種是實現(xiàn)Runnable接口。具

    • 實現(xiàn)Runnable接口
    • 繼承Thread類

    注意:線程的啟動是調(diào)用start()方法,而不是run()方法!

    舉例并進行解釋

    1.直接調(diào)用run方法實例:

    public class TestTheadDemo { public static void main(String[] args) { for (int i = 0; i < 10; i++) { ThreadTest thread = new ThreadTest(); thread.run();// thread.start(); } }}class ThreadTest extends Thread{ @Override public void run() { System.out.println("當前線程 : " + Thread.currentThread().getName()); }}

    運行結(jié)果 :當前線程全部是main線程,相當于ThreadTest類的thread對象直接調(diào)用了run()方法。(直接調(diào)用run方法只是一個普通的單線程程式)

    當前線程 : main當前線程 : main當前線程 : main當前線程 : main當前線程 : main

    2.調(diào)用start()方法 將上面的代碼 注釋的thread.start();打開, thread.run();注釋!

    運行結(jié)果 :發(fā)現(xiàn)啟動了不同的線程進行執(zhí)行。

    當前線程 : Thread-0當前線程 : Thread-5當前線程 : Thread-3當前線程 : Thread-4當前線程 : Thread-2當前線程 : Thread-1當前線程 : Thread-7當前線程 : Thread-6當前線程 : Thread-9

    查看start()方法的源碼中,發(fā)現(xiàn)有個地方

    public synchronized void start() { //代碼省略.... try { start0();//注意這個地方,調(diào)用了native本地方法 started = true; } finally { //代碼省略.... } } //本地方法 private native void start0();

    總結(jié): 調(diào)用start()方法,虛擬機JVM通過執(zhí)行本地native方法start0和操作系統(tǒng)cup進行交互,此時線程并沒有正在立即執(zhí)行,而是等待cup的調(diào)度,當cpu分配給線程時間,線程才執(zhí)行run()方法!

    更多相關(guān)內(nèi)容可以參考 [java多線程編程核心技術(shù): 高洪巖 ] :https://book.douban.com/subject/26555197/


    7、Lock與Synchronized的區(qū)別

    在Java中Lock與Synchronized都可以進行同步操作,保證線程的安全,就如上面第一問提到的,線程安全性問題。下面進行簡單的額介紹!

    (1)、Synchronized的簡單介紹

    synchronized同步的原理

    關(guān)鍵字synchronized可以修飾方法或者以同步塊的形式來使用,它主要確保多個線程在同一時刻,只能有一個線程處于方法或者同步塊 中,保證了線程對變量訪問的可見性和排他性。

    synchronized同步實現(xiàn)的基礎(chǔ)

  • 普通同步方法,鎖是當前實例對象
  • 靜態(tài)同步方法,鎖是當前類的class對象
  • 同步方法塊,鎖是括號里面的對象
  • [一張圖講解對象鎖和關(guān)鍵字synchronized修飾方法(代碼塊] :http://blog.csdn.net/u010648555/article/details/78138225

    【死磕Java并發(fā)】-----深入分析synchronized的實現(xiàn)原理]http://blog.csdn.net/chenssy/article/details/54883355

    注:有興趣也可以看看 volatile關(guān)鍵字!

    關(guān)鍵字volatile可以用來修飾字段(成員變量),就是告知程序任何對該變量的訪問均需要從共享內(nèi)存中獲取,而對它的改變必須同步刷新回共享內(nèi)存中,保證所有線程對變量訪問的可見性。

    關(guān)鍵字volatile和關(guān)鍵字synchronized均可以實現(xiàn)線程間通信!

    (2)、Lock的簡單介紹

    首先明確Lock是Java 5之后,在java.util.concurrent.locks包下提供了另外一種方式來實現(xiàn)同步訪問。 Lock是一個接口,其由三個具體的實現(xiàn):ReentrantLock、ReetrantReadWriteLock.ReadLock 和 ReetrantReadWriteLock.WriteLock,即重入鎖、讀鎖和寫鎖。增加Lock機制主要是因為內(nèi)置鎖存在一些功能上局限性。

    Java并發(fā)編程系列之十六:Lock鎖 : http://blog.csdn.net/u011116672/article/details/51064186

    區(qū)別總結(jié): 1.synchronized是Java語言的關(guān)鍵字,Lock是一個類,通過這個類可以實現(xiàn)同步訪問;

    2.synchronized是在JVM層面上實現(xiàn)的,不但可以通過一些監(jiān)控工具監(jiān)控synchronized的鎖定,而且在代碼執(zhí)行時出現(xiàn)異常,JVM會自動釋放鎖定,但是使用Lock則不行,Lock是通過代碼實現(xiàn)的,要保證鎖定一定會被釋放,就必須將unLock(),最好放到finally{}中。 3.Lock有ReetrantLock(可重入鎖)實現(xiàn)類,可選的方法比synchronized多,使用更靈活。 4..并不是Lock就比synchronized一定好,因為synchronized在jdk后面的版本也在不斷優(yōu)化。在資源競爭不是很激烈的情況下,synchronized的性能要優(yōu)于ReetrantLock,但是在資源競爭很激烈的情況下,synchronized的性能會下降很多,性能不如Lock。

    Lock和synchronized的區(qū)別和使用:http://www.cnblogs.com/baizhanshi/p/6419268.html

    8、JVM的內(nèi)存結(jié)構(gòu)

    下圖:【圖片版本-深入理解Java虛擬機:JVM高級特性與最佳實踐:周志明】

    Jvm內(nèi)存模型

    ? 還有這個博文: JVM內(nèi)存結(jié)構(gòu)圖解 :http://blog.csdn.net/coffeelifelau/article/details/52534672

    9、請解釋如下jvm參數(shù)的含義

    -server -Xms512m -Xmx512m -Xss1024K -Xmn256m-XX:PermSize=256m -XX:MaxPermSize=512m -XX:MaxTenuringThreshold=20 -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly

    -server :服務器模式 注:JVM client模式和server模式,生產(chǎn)環(huán)境請使用-server,性能更好! [JVM client模式和Server模式的區(qū)別]:https://zhidao.baidu.com/question/1703232626938481420.html

    -Xms512m :JVM初始分配的堆內(nèi)存,一般和Xmx配置成一樣以避免每次gc后JVM重新分配內(nèi)存。

    -Xmx512m :JVM最大允許分配的堆內(nèi)存,按需分配

    -Xss1024K :設(shè)置每個線程的堆棧大小

    -Xmn256m :年輕代內(nèi)存大小,整個JVM內(nèi)存=年輕代 + 年老代 + 持久代

    -XX:PermSize=256m :設(shè)置持久代(perm gen)初始值,默認物理內(nèi)存的1/64(注意:jdk 8 已經(jīng)沒有此參數(shù))

    -XX:MaxPermSize=512m : 設(shè)置持久代最大值(注意:jdk 8 已經(jīng)沒有此參數(shù))

    **-XX:MaxTenuringThreshold=20 ** :垃圾最大年齡

    **-XX:CMSInitiatingOccupancyFraction=80 ** :使用cms作為垃圾回收 使用80%后開始CMS收集

    -XX:+UseCMSInitiatingOccupancyOnly :使用手動定義初始化定義開始CMS收集

    還有很多很多參數(shù)。。。。

    [一個性能較好的JVM參數(shù)配置] :http://developer.51cto.com/art/201507/486162.htm

    10 、數(shù)據(jù)庫隔離級別有哪些,各自的含義是什么,MYSQL默認的隔離級別是是什么?

    事務指定了4種隔離級別(從弱到強分別是):

  • Read Uncommitted:讀未提交
  • Read Committed:讀提交
  • Repeatable Read:重復讀
  • Serializable:序列化
  • 1:Read Uncommitted(讀未提交):一個事務可以讀取另一個未提交事務的數(shù)據(jù)。

    2:Read Committed(讀提交):一個事務要等另一個事務提交后才能讀取數(shù)據(jù)。

    3:Repeatable Read(重復讀):在開始讀取數(shù)據(jù)(事務開啟)時,不再允許修改操作。

    4:Serializable(序列化):Serializable 是最高的事務隔離級別,在該級別下,事務串行化順序執(zhí)行,可以避免臟讀、不可重復讀與幻讀。

    大多數(shù)數(shù)據(jù)庫默認的事務隔離級別是Read committed,比如Sql Server , Oracle。MySQL的默認隔離級別是Repeatable read。

    在事務的并發(fā)操作中可能會出現(xiàn)臟讀(dirty read),不可重復讀(repeatable read),幻讀(phantom read)。可參考:[理解事務的4種隔離級別]:http://blog.csdn.net/qq_33290787/article/details/51924963

    注:Mysql查詢事務隔離級別: 查詢命令總結(jié):

    查看當前會話隔離級別:select @@tx_isolation;查看系統(tǒng)當前隔離級別:select @@global.tx_isolation;設(shè)置當前會話隔離級別:set session transaction isolation level repeatable read;設(shè)置當前會話隔離級別:set global transaction isolation level repeatable read;

    謝謝你的閱讀,如果您覺得這篇博文對你有幫助,請點贊或者喜歡,讓更多的人看到!祝你每天開心愉快!


    不管做什么,只要堅持下去就會看到不一樣!在路上,不卑不亢!

    博客首頁 : http://blog.csdn.net/u010648555

    愿你我在人生的路上能都變成最好的自己,能夠成為一個獨擋一面的人

    ? 每天都在變得更好的阿飛云

    總結(jié)

    以上是生活随笔為你收集整理的arraylist线程安全吗_Java的线程安全、单例模式、JVM内存结构等知识梳理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。