#在千鋒“逆戰”學習第30天#周總結

周總結
眨眼間已經學習三十天,周總結的意義就是把本週學過的知識從頭到尾再過一遍,會有許多新的理解,當時有些似懂非懂的地方再看過去也會透徹。一遍一遍夯實自己的基礎吧。

異常
概念:程序在運行過程中出現的特殊情況
異常處理的必要性:任何程序都可能存在大量的未知結果、錯誤;如果不對這些問題進行正確處理,則可能導致程序的中斷,造成不必要的損失。

異常的分類
Throwable:可拋出的,一切錯誤或異常的父類,位於java.lang包中
Error:JVM、硬件、執行邏輯錯誤,不能手動處理。
Exception:程序在運行和配置中產生的問題,可處理。
RuntimeException:運行時異常,可處理,可不處理。
CheckedException:受查異常,必須處理。

異常的產生
自動拋出異常:當程序運行時,遇到不符合規範的代碼或結果時,會產生異常。
手動拋出異常:語法:throw new 異常類型(“實際參數”);
產生異常結果:相當於遇到return語句,導致程序因異常而終止

異常的傳遞
異常的傳遞:按照方法的調用鏈反向傳遞,如始終沒有處理異常,最終會由JVM進行默認異常處理(打印堆棧跟蹤信息)

受查異常:throws 聲明異常,修飾在方法參數列表後端。

運行時異常:因可處理可不處理,無需聲明異常

異常的處理
在這裏插入圖片描述
常見的異常處理結構
在這裏插入圖片描述

自定義異常
需繼承Exception或Exception子類,常用RuntimeException

必須提供的構造方法:
無參構造方法
String message參數的構造方法

方法覆蓋
帶有異常聲明的方法覆蓋
方法名、參數列表、返回值類型必須和父類相同
子類的訪問修飾符和父類一樣或者比父類更寬
子類中的方法,不能拋出比父類更寬的異常,但是可以拋出比父類更多的異常

多線程

什麼是進程
程序是靜止的,只有程序運行時才能稱爲進程。

單核CPU在任何時間點上只能運行一個進程,宏觀並行,微觀串行。

什麼是線程
線程,又稱輕量級進程,程序中的一個順序控制流程,同時也是CPU的基本調度單位。進程由多個線程組成,彼此間完成不同的工作,交替執行,稱爲多線程。

線程的組成

任何一個線程都有基本的組成部分:

CPU時間片:操作系統(OS)會爲每個線程分配執行時間

運行數據:
	堆空間:存儲線程需使用的對象,多個線程可共享堆中的對象
	棧空間:存儲線程需要使用的局部變量,每個線程都擁有獨立的棧

線程的邏輯代碼			

創建線程

創建線程的第一種方式:
1、繼承Theard類
2、覆蓋run()方法
3、創建子類對象
4、調用start()方法

創建線程的第二種方式:
1、實現Runnable接口
2、覆蓋run()方法
3、創建實現類對象
4、創建線程對象(注意需要將創建的實現類對象傳入線程對象)
5、調用start()方法

常見方法

休眠
public static void sleep(long millis)
當前線程主動休眠millis毫秒

放棄
public static void yield()
當前線程主動放棄時間片,回到就緒狀態,競爭下一次時間片

結合
public final void join()
允許其他線程加入到當前線程(待加入線程結束後再運行當前線程)

線程的狀態
在這裏插入圖片描述

線程的安全問題
在這裏插入圖片描述
線程不安全:
當多線程併發訪問臨界資源時,如果破壞原子操作,可能會造成數據不一致
臨界資源:共享資源(同一對象),一次僅允許一個線程使用,纔可確保其正確性
原子操作:不可分割的多步操作,被視作一個整體,其順序和步驟不可打亂或缺省

同步方式(1)
同步代碼塊:
synchronized(臨界資源對象){//對臨界對象資源加鎖
代碼//原子操作
}

注:每個對象都有一個互斥鎖標記,用來分配給線程的
只有擁有互斥鎖標記的線程,才能進入該對象加鎖的同步代碼塊
線程退出同步代碼塊時,會釋放相應的互斥鎖標記

同步方式(2)
同步代碼塊:
synchronized 返回值類型 方法名稱(形參列表0){//對當前對象(this)加鎖
//代碼(原子操作)
}

注:
只有擁有對象互斥鎖標記的線程,才能進入該對象加鎖的同步方法中
線程退出同步方法時,會釋放相應的互斥鎖標記

同步規則
注意:
只有在調用包含同步代碼塊的方法,或者同步方法時,才需要對象的鎖標記
如調用不包含同步代碼塊的方法,或普通方法時,則不需要鎖標記,可直接調用

已知JDK中線程安全的類:
StringBuffer
Vector
Hashtable
以上類中的公開方法,均爲synchronized修飾的同步方法

經典問題

死鎖
當一個線程擁有A對象鎖標記,並等待B對象鎖標記,同時第二個線程擁有B對象鎖標記,並等待A對象鎖標記時,產生死鎖。
一個對象可同時擁有多個對象的鎖標記,當線程阻塞時,不會釋放已經擁有的鎖標記,由此可能造成死鎖。

生產者、消費者
若干個生產者在生產產品,這些產品將提供給若干個消費者去消費,爲了使生產者和消費者能併發執行,在兩者之間設置一個能儲存多個產品的緩衝區,生產者將生產的產品放入緩衝區,消費者從緩衝區取走產品進行消費,顯然生產者和消費者之間必須保持同步,既不允許消費者到一個空緩衝區中取產品,也不允許生產者向一個滿的緩衝區放入產品。

線程通信

等待
public final void wait()
public final void wait(long timeout)
必須在對obj加鎖的同步代碼塊中。在一個線程中,調用obj.wait()時,此線程會釋放其擁有的所有鎖標記。同時此線程阻塞在o的等待隊列中,釋放鎖,進入等待隊列。

通知
public final void notify()
public final void notifyAll()
必須在對obj加鎖的代碼塊中,從obj的Wainting中釋放一個或全部線程,對自身沒有任何影響

高級多線程

線程池概念
現有問題
線程是寶貴的內存資源,單個線程約佔1MB空間,過多分配易造成內存溢出
頻繁的創建及銷燬進程會增加虛擬機回收頻率,資源開銷,造成程序性能下降
線程池
線程容器,可設定線程分配的容量上限
將預先創建的線程對象存入池中,並重複用線程池中的線程對象
避免頻繁的創建和銷燬
在這裏插入圖片描述
獲取線程池
Executor:線程池的頂級接口

ExecutorService:線程池接口,可通過submit(Runnable task)提交任務代碼

Executors工廠類:通過此類可以獲得一個線程池

通過newFixedThreadPool(int nThread)獲取固定數量的線程池。參數:指定線程池中線程的數量

通過newCachedThreadPool()獲得動態數量的線程池,如不夠創建新的,沒有上限

Callable接口
public interface Callable{
public V call() throws Exception;
}
JDK5加入,與Runnable接口類似,實現之後代表一個線程任務。
Callable具有泛型返回值、可以聲明異常

Future接口
概念:異步接收ExecutorService.submit()所返回的狀態結果,當中包含了call()的返回值

方法:V get()以阻塞形式等待Future中的異步處理結果(call()的返回值)

在這裏插入圖片描述
在這裏插入圖片描述

Lock接口
JDK5加入,與synchronized比較,顯式定義,結構更靈活

提供更多實用性方法,功能更強大,性能更優越

常用方法:
void lock()//獲取鎖,如鎖被佔用,則等待
boolean tryLock()//嘗試獲取鎖
void unlock()//釋放鎖

重入鎖
ReentrantLock:Lock接口的實現類,與sychronized一樣具有互斥鎖功能。
在這裏插入圖片描述
讀寫鎖
ReentrantReadWriteLock:
一種支持一寫多讀的同步鎖,讀寫分離,可分別分配讀鎖,寫鎖。
支持多次分配讀鎖,使多個讀操作可以併發執行。

互斥規則:
寫-寫:互斥,阻塞
讀-寫:互斥,讀阻塞寫、寫阻塞讀
讀-讀:不互斥、不阻塞

在讀操作遠遠高於寫操作的環境中,可在保障線程安全的情況下,提高運行效率。
在這裏插入圖片描述
線程安全的集合
在這裏插入圖片描述
Collections中的工具方法
Collections工具類中提供了多可以獲得線程安全集合的方法

public static <T> Collection<T> synchronizedCollection(Collection<T> c)
public static <T> List<T> synchronizedList(List<T> list)
public static <T> Set<T> synchronizedSet(Set<T> s)
public static <K,V>Map<K,V>synchronizedMap(Map<K,V> m)
public static <T>SortedSet<T>synchronizedSortedSet(SortedSet<T> s)
public static <K,V>SortedMap<K,V>synchronizedSortedMap(SortedMap<K,V> m)

JDK1.2提供,接口統一、維護性高,但性能沒有提升,均以synchronized實現

CopyOnWriteArrayList
線程安全的ArrayList,加強版讀寫分離
寫有鎖,讀無鎖,讀寫之間不阻塞,優於讀寫鎖
寫入時,先copy一個容器副本,再添加新元素,最後替換引用
使用方法與ArrayList無異

CopyOnWriteArraySet
線程安全的Set,底層使用CopyOnWriteArrayList實現
唯一不同在於,使用addIfAbsent()添加元素,會遍歷數組
如存在元素,則不添加(扔掉副本)

ConcurrentHashMap
初始容量默認爲16段(Segment),使用分段鎖設計
不對整個Map加鎖,而是爲每個Segment加鎖
當多個對象存入同一個Segment時,才需要互斥
最理想狀態爲16個對象分別存入16個Segment,並行數量16
使用方式與HashMap無異

Queue接口(隊列)
Collection的子接口,表示隊列FIFO(First In First Out 先進先出)

常用方法:
拋出異常:
boolean add(E e)//順序添加一個元素(到達上限後,再添加則會拋出異常)
E remove()//獲得第一個元素並移除(如果隊列沒有元素,則拋出異常)
E element()//獲得第一個元素但不移除(如果隊列沒有元素,則拋出異常)

返回特殊值(推薦使用):
boolean offer(E e)//順序添加一個元素(到達上線後,在添加則會返回false)
E poll()//獲得第一個元素並移除(如果隊列沒有元素時,則返回null)
E keep()//獲得第一個元素但不移除(如果隊列沒有元素時,則返回null)

ConcurrentLinkedQuene
線程安全,可高效讀寫的隊列,高併發下性能最好的隊列
無鎖,CAS比較交換算法,修改的方法包括三個核心參數(V,E,N)
V:要更新的變量
E:預期值
N:新值
只有當V==E時,V=N;否則表示已被更新過,則取消當前操作

BolckingQuene接口(阻塞隊列)
Quene的子接口,阻塞的隊列,增加了兩個線程狀態爲無限期等待的方法

方法:
void put(E e)//將指定元素插入此隊列中,如果沒有可用空間,則等待
E take()//獲取並移除此隊列頭部元素,如果沒有可用元素,則等待

可用於解決生產者、消費者問題

阻塞隊列
ArrayBlockingQuene:
數組結構實現,有界隊列(手工固定上限)

LinkedBlockingQuene:
鏈表結構實現,無界隊列(默認上限Integer.MAX_VALUE)

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