多線程知識總結
多線程
創建線程的兩種方式
1.繼承Thread,覆蓋父類Run方法
2.實現Runable接口,重寫Run方法
多線程機制並沒有提高程序的運行效率,只是因爲開啓了多個線程,佔用了服務器更多的帶寬。
定時器
Timer
TimerTask
new Timer().schedule(new TimerTask(){
@override
public void run(){
}
},多少秒後執行run,前面執行後每隔多少秒再執行一次run);
線程間的互斥與同步通信
1.方法簽名上添加Synchronized
2.需要同步的代碼封裝到Synchronized塊中
Synchronized(該同步塊所在類的字節碼對象){
}
經驗:
要用到共同數據(包括同步鎖)的若干個方法,都應該將這些方法歸在同一個類中,這種設計
符合高內聚,和程序的健壯性,便於維護。
經驗:
有些時候,線程會發生僞喚醒的情況,此時在同步塊內使用while(){}判斷,會比使用if更具有健壯性。
因爲if只會判斷一次,符合條件就進入。而while在循環結束後,還會判斷一次。
經驗:
代碼編寫過程中,某些運算符,本身包含邏輯的處理,如三元運算,本身就有true和false的判斷,
就不需要再使用邏輯判斷了。
還有if中,不需要再添加邏輯判斷。
ThreadLocal實現線程範圍的共享變量
變量 ThreadLocal<Integer> x = new ThreadLocal<>();
自定義類 ThreadLocal<MyObject> myObject = new ThreadLocal<>();
使用單例模式+單例類中,私有化一個靜態的ThreadLocal<單例類> = new ThreadLocal<>(),
將單例對象放入ThreadLocal中,每次獲取時,先判斷ThreadLocal中有沒有,有就取出,並返回,
沒有就new一個,存入ThreadLocal,並返回。
來保證數據在該單例中被共享。
全局的ThreadLocal變量中,當多個線程使用set方法往裏面存值後,就相當於往裏面的map存儲多條
記錄,key分別是各個線程的線程名。當線程結束時,ThreadLocal會自動將死亡的線程釋放。
可以調用ThreadLocal的clear方法,將線程全部清空。
多個線程訪問共享對象和數據的方式
1.如果每個線程執行的代碼相同,可以使用同一個Runnable對象,這個Runable中封裝共享數據,和對數據的操作。例如
買票系統。
2.如果每個系統執行的代碼不同,
2.1 將共享數據封裝到一個對象中,然後將對象通過實現Runnable接口對象的構造方法逐一傳遞給各個Runable對象,每個線程對
共享數據的操作方法也放到該對象中,這樣容易實現針對該數據進行的各個操作的互斥和通信。
2.2 將這些Runnable對象作爲某一個類中的內部類,共享數據作爲這個外部類中的成員變量,
每個線程對共享數據的操作方法也分配給外部類。以便實現對共享數據進行的各個操作的互斥和通信,
作爲內部類的各個Runable對象調用外部類的這些方法。
2.3 將共享數據封裝到另一個對象中,每個線程對共享數據的操作方法也分配到那個對象中,對象作爲這個外部類
中的成員變量或方法中的局部變量,每個線程的Runable對象作爲外部類中的成員內部類或局部內部類。
(定義一個類,類中將共享數據定義爲成員變量,並提供對該變量的操作函數,函數使用synchronized修飾,再定義多個實現了Runnable接口
口的成員內部類,該成員內部類通過內部Run方法調用同一級別的對共享數據操作的成員方法)
java5提供了線程併發庫
java.util.concurrent包
automic 提供了對於基本數據類型,和類中基本數據類型的原子性操作。
AutomicInteger
java.utl.concurrent.atomic包
線程池ExecutorService threadPool =
1.固定線程池 Executors.newFixedThreadPool(3);
2.緩存線程池 Executors.newCachedThreadPool();
3.單一線程池 Executors.newSingleThreadExecutor();(實現線程死掉後重新啓動 其實就是在線程死掉後,使用原有引用變量指向一個新的線程)
關閉線程池
shutdown 所有任務執行完後,關閉所有線程
shutdownNow 當前任務完成後,關閉所有線程
線程池任務調度:給線程池中線程分配任務。可以分配多個schedule()
Executors.newScheduledThreadPool(3).schedule(Runnable,delay,unit);
Callable&Future
Future取得的結果類型必須與Callable返回的結果類型一致,通過泛型實現。
Callable採用ExecutorService的submit()方法提交,返回的future對象可以取消任務。
Future<T> future = threadPool.submit(new Callable<T>(){
public String call() throws Exception{
//Thread.sleep(2000);
return t.type = T;
}
});
future.get();
CompletionService 用於提交一組Callable任務,其take方法返回已完成的一個Callable任務對應的Futurure
對象。類似qq種菜機制,中下一波種子,優先成熟的可以收穫或偷取。
CompletionService<V> c = new ExecutorCompletionService<V>
Lock&Condition實現線程同步通信
Lock比傳統線程模型中的Synchronized方式更加面向對象,與生活中的鎖類似,鎖本身也應該是一個對象,
兩個線程執行的代碼片段要實現同步互斥的效果,它們必須用同一個Lock對象,鎖是在代表要操作的資源的
類的內部方法中,而不是線程代碼中。
使用Lock注意事項
1.多個線程的lock對象必須一致.
2.lock需要放在線程訪問的共享資源中。
Lock是一個接口
實現類有ReentrantLock
方法
lock.lock();
try{
需要鎖住的代碼
}finally{
//執行完成後,必須釋放鎖,不然可能會導致線程死在鎖住的代碼中,後續線程無法進入。
lock.unlock();
}
讀寫鎖,限制代碼在執行過程中是否允許同步執行讀或寫的操作。
對讀寫方法中,具體執行讀寫操作的代碼上鎖
讀方法上讀鎖
寫方法上寫鎖
接口ReadWriteLock
實現類 ReentrantReadWriteLock
lock.readLock().lock();
try{
需要上讀鎖的代碼
}finally{
lock.readLock().unlock();
}
lock.writeLock().lock();
try{
}finally{
lock.writeLock.unlock();
}
Lock可以替代Synchronize完成線程互斥
Condition可以替代Object.wait()和Object.notify()完成同步通信
Condition condition = lock.newCondition();
condition.await();
condition.signal();
信號燈
Semaphore可以控制同時訪問資源的線程個數。例如:實現文件的併發訪問。
Semaphore sp = new Semaphore(3);
acquire()獲得一個許可
release()釋放一個許可
Semaphore對象可以實現互斥鎖的功能,並且可以是由一個線程獲得了“鎖”,再由另一個線程釋放
“鎖”,這可應用於死鎖恢復的一些場合。
工具類
CyclicBarrier 彼此等待,集合後分散活動 ,分散活動後在指定地點集合,集合後再分散。
CountDownLatch 倒計時記時器 實現裁判吹口號,運動員起跑,運動員都到達終點後,開始評判成績。
Exchanger 用於實現兩個人之間的數據交換,每個人在完成一定的事務後想與對方交換數據,第一個先拿
出數據的人將一直等待第二個人拿着數據到來時,才能彼此交換數據。
阻塞隊列
接口BlockingQueue 沒有值時報異常 沒有值時爲null 沒有值時阻塞,等待有值(無值)時,進行存取。
ArrayBlockingQueue 存值的方式有三種,add offer put put() take()會產生阻塞
取值的方式有三種 , remove poll take
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.