摘要:需要注意的是對于方法或者代碼塊,當出現異常時,會自動釋放當前線程占用的鎖,因此不會由于異常導致出現死鎖現象。用于實現線程間的通信,它是為了解決難以使用的問題。
速度StringBuilder>StringBuffer>String,StringBuffer線程安全
線程安全的集合有:Vector、Stack、HashTable、ConcurrentHashMap、
CopyOnWriteXXX(如CopyOnWriteArrayList)
ClassLoader
程序在啟動的時候,并不會一次性加載程序所要用的所有class文件,而是根據程序的需要,通過Java的類加載機制(ClassLoader)來動態加載某個class文件到內存當中的,從而只有class文件被載入到了內存之后,才能被其它class所引用。所以ClassLoader就是用來動態加載class文件到內存當中用的。Java默認提供的三個ClassLoader。BootStrap ClassLoader:稱為啟動類加載器,是Java類加載層次中最頂層的類加載器,負責加載JDK中的核心類庫,如:rt.jar、resources.jar、charsets.jar等。
Extension ClassLoader:稱為擴展類加載器,負責加載Java的擴展類庫,默認加載JAVA_HOME/jre/lib/ext/目下的所有jar。
App ClassLoader:稱為系統類加載器,負責加載應用程序classpath目錄下的所有jar和class文件。
ClassLoader使用的是雙親委托模型來搜索類的,每個ClassLoader實例都有一個父類加載器的引用(不是繼承的關系,是一個包含的關系),虛擬機內置的類加載器(Bootstrap ClassLoader)本身沒有父類加載器,但可以用作其它ClassLoader實例的的父類加載器。
JVM在判定兩個class是否相同時,不僅要判斷兩個類名是否相同,而且要判斷是否由同一個類加載器實例加載的。只有兩者同時滿足的情況下,JVM才認為這兩個class是相同的
Java ClassLoader原理
synchronized lock
淺談Java并發編程系列(五)Java并發編程之線程同步
當一個線程正在訪問一個對象的synchronized方法,那么其他線程不能訪問該對象的其他synchronized方法,因為一個對象只有一把鎖,當一個線程獲取了該對象的鎖之后,其他線程無法獲取該對象的鎖,所有無法訪問該對象的其他synchronized方法。
當一個線程正在訪問一個對象的synchronized方法,那么其他線程能訪問該對象的非synchronized方法。因為非synchronized方法不需要獲取該對象的鎖。
如果一個線程A需要訪問對象object1的synchronized方法fun1,另外一個線程B需要訪問對象object2的synchronized方法fun1,即使object1和object2是同一類型,也不會產生線程安全問題,因為他們訪問的是不同的對象,所以不存在互斥問題。
如果一個線程執行一個對象的非static synchronized方法,另一個線程執行這個對象所屬類的static synchronized方法,此時不會發生互斥現象,因為訪問static synchronized方法占用的是類鎖,而訪問非static synchronized方法占用的是對象鎖,所以不存在互斥現象。
需要注意的是:對于synchronized方法或者synchronized代碼塊,當出現異常時,JVM會自動釋放當前線程占用的鎖,因此不會由于異常導致出現死鎖現象。
顯式鎖ReentrantLock則可以將鎖的獲得和釋放分開。同時顯式鎖可以提供輪訓鎖和定時鎖,同時可以提供公平鎖或者非公平鎖。
ReentrantLock和Condition的關系
在ReentrantLock類中有一個重要的函數newCondition(),該函數用于獲取lock上的一個條件,也就是說Condition是和Lock綁定的。Condition用于實現線程間的通信,它是為了解決Object.wait()、notify()、notifyAll()難以使用的問題。
public class MyArrayBlockingQueue{ // 數據數組 private final T[] items; // 鎖 private final Lock mLock = new ReentrantLock(); // 數組滿的條件 private Condition notFull = mLock.newCondition(); // 數組空的條件 private Condition notEmpty = mLock.newCondition(); // 頭部 private int head; // 尾部 private int tail; // 數據數量 private int count; public MyArrayBlockingQueue(int maxSize) { // TODO Auto-generated constructor stub items = (T[]) new Object[maxSize]; } public MyArrayBlockingQueue() { // TODO Auto-generated constructor stub this(10); } public void put(T t) { mLock.lock(); try { // 如果數據已滿,等待 while (count == getCapacity()) { System.out.println("數據已滿,請等待"); notFull.await(); } System.out.println("存入數據"); items[tail] = t; if (++tail == getCapacity()) { tail = 0; } ++count; // 喚醒等待數據的線程 notEmpty.signalAll(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { mLock.unlock(); } } public T take() { mLock.lock(); try { // 如果數組數據為空,則阻塞 while (count == 0) { System.out.println("還沒有數據,等待"); notEmpty.await(); } System.out.println("取出數據"); T t = items[head]; items[head] = null; if (++head == getCapacity()) { head = 0; } --count; // 喚醒添加數據的線程 notFull.signalAll(); return t; } catch (InterruptedException e) { // TODO: handle exception } finally { mLock.unlock(); } return null; } public int getCapacity() { return items.length; } public int size() { mLock.lock(); try { return count; } finally { mLock.unlock(); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub final MyArrayBlockingQueue mQueue = new MyArrayBlockingQueue<>( 5); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while (true) { for(int i = 0;i < 3;i++) mQueue.put("just"); try { Thread.sleep(50); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while (true) { mQueue.take(); } } }).start(); } } 結果打印 存入數據 存入數據 存入數據 取出數據 取出數據 取出數據 還沒有數據,等待 存入數據 存入數據 存入數據 取出數據 取出數據 取出數據 還沒有數據,等待
當時看到這段代碼我就想到一個問題:如果一個線程lock()對象后被掛起還沒有unlock,那么另外一個線程就拿不到鎖了(lock()操作會掛起),那么就無法通知(notify)前一個線程,這樣豈不是“死鎖”了?再回頭看代碼,不管take()還是put(),在進入lock.lock()后唯一可能釋放鎖的操作就是await()了。也就是說await()操作實際上就是釋放鎖,然后掛起線程,一旦條件滿足就被喚醒,再次獲取鎖!
await源碼如下
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); int interruptMode = 0; while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); }
完整的await()操作是安裝如下步驟進行的:
將當前線程加入Condition鎖隊列。特別說明的是,這里不同于AQS的隊列,這里進入的是Condition的FIFO隊列。后面會具體談到此結構。進行2。
釋放鎖。這里可以看到將鎖釋放了,否則別的線程就無法拿到鎖而發生死鎖。進行3。
自旋(while)掛起,直到被喚醒或者超時或者CACELLED等。進行4。
獲取鎖(acquireQueued)。并將自己從Condition的FIFO隊列中釋放,表明自己不再需要鎖(我已經拿到鎖了)。
介紹Condition的數據結構。我們知道一個Condition可以在多個地方被await*(),那么就需要一個FIFO的結構將這些Condition串聯起來,然后根據需要喚醒一個或者多個(通常是所有)。所以在Condition內部就需要一個FIFO的隊列。
//conditon 的兩個屬性 private transient Node firstWaiter; private transient Node lastWaiter;
這兩個節點就是描述一個FIFO的隊列。我們再結合前面提到的節點(Node)數據結構。我們就發現Node.nextWaiter就派上用場了!nextWaiter就是將一系列的Condition.await*串聯起來組成一個FIFO的隊列。
wait和sleep的區別
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70373.html
摘要:,看到很多文章把理解為暫停,其實是不準確的,翻譯過來用讓步更為準確一些。如下在中我們可以看到官方的解釋,更多的是作為調試或測試時候使用也就是瘋狂重分配,提高切換概率,模擬并發 yield,看到很多文章把yield理解為暫停,其實是不準確的,翻譯過來用讓步更為準確一些。簡單描述下其作用: 使調用yield的正在執行的線程讓出cpu,讓同等優先權的其他線程包括自身重新進行分配調度 概念性的...
摘要:問題描述遇到一個題目經過強制類型轉換以后,變量,的值分別為多少答案是這涉及到的,打算借此稍稍研究一下。分為兩種,一是擴展型基本數據類型轉換,二是窄化型基本數據類型轉換。需要注意的是是有可能丟失數值的整體信息以及損失精度和范圍的。 問題描述 遇到一個題目: 經過強制類型轉換以后,變量a,b的值分別為多少? short a = 128; byte b = (byte) a;a = ?,...
摘要:正如我標題所說,簡歷被拒??戳宋液啔v之后說頭條競爭激烈,我背景不夠,點到為止。。三準備面試其實從三月份投遞簡歷開始準備面試到四月份收,也不過個月的時間,但這都是建立在我過去一年的積累啊。 本文是 無精瘋 同學投稿的面試經歷 關注微信公眾號:進擊的java程序員K,即可獲取最新BAT面試資料一份 在此感謝 無精瘋 同學的分享 目錄: 印象中的頭條 面試背景 準備面試 ...
摘要:正如我標題所說,簡歷被拒。看了我簡歷之后說頭條競爭激烈,我背景不夠,點到為止。。三準備面試其實從三月份投遞簡歷開始準備面試到四月份收,也不過個月的時間,但這都是建立在我過去一年的積累啊。 本文是 無精瘋 同學投稿的面試經歷 關注微信公眾號:進擊的java程序員K,即可獲取最新BAT面試資料一份 在此感謝 無精瘋 同學的分享目錄:印象中的頭條面試背景準備面試頭條一面(Java+項目)頭條...
摘要:代碼實現在控制臺打印總結本篇文章帶大家搭好環境,并體驗了控制臺打印。輸出結果總結熟練掌握取余和整除運算,大有作用。終止本次循環,繼續執行下一次循環。 ?本文收錄...
閱讀 2977·2023-04-25 17:22
閱讀 1542·2019-08-30 15:54
閱讀 1270·2019-08-30 15:53
閱讀 1787·2019-08-30 15:43
閱讀 3020·2019-08-29 12:29
閱讀 1232·2019-08-26 11:37
閱讀 3255·2019-08-23 18:02
閱讀 1604·2019-08-23 14:15