---
title: Multi Thread
---
###### tags: `JAVA`
[Toc]
# multi thread 的使用方式
1. extend Thead
2. implement Runnable
1,2 屬於早期java的用法,沒有辦法接收回傳值,必須通過其他的方式,例如線程間通信、共享變數,現在已經少用。 在兩者間選擇,盡可能選用implement runnable, 保留繼承的彈性。
在無需回傳值及簡易的情境,採用java 1.8 lambda方式 new thread,比起其他方式更為輕便:https://github.com/ronnielin8862/java19_practice/blob/main/src/main/java/org/example/freePractice/concucrency/lock/nolock/MainFunc.java
3. callable and future https://www.cnblogs.com/qlqwjy/p/9657981.html
java 1.5以後新增 方式 3: implement callable 的 class 編寫任務,透過futureTask獲取結果。
練習(此處採用exutorService方式): https://github.com/ronnielin8862/java-practice/blob/dev/src/main/java/multiThread/startMultiThread/PracticeCallable.java
4. completableFuture (c.f.)
java 1.8 以後增加方式4 ,以彌補 future接收回傳值需要阻塞線程的缺點,並且增加了不同的方式處理回傳值,達成更靈活的線程操作
cf的方式需要特別留意的地方是,預設會採用全局forkjoin線程池,而forkjoin線程池預設的thread pool是cpu核心數 (在某些具有cpu超核心技術的設備上,邏輯核與實體核不同時,是以邏輯核計算)。 在應用場景具備多線程的情況,無法充分發揮多線程的優勢,尤其是當線程工作內容具有大量io的cpu等候時間的情況。或者當在某些場景包括練習的時候,使用sleep()時,也會導致其他線程無法運行,直到既有的線程完成工作,才會開啟新線程。
因此在使用cf時,建議自定義executor線程池,並帶入cf運行,才是正確的使用姿勢。 https://github.com/ronnielin8862/java19_practice/blob/main/src/main/java/org/example/freePractice/concucrency/heap/wait/HeapA.java
# multi thread 的阻塞與喚醒
1. sleep
2. suspend() 和 resume()
这两个 API 是过期的,也就是不建议使用的。
不推荐使用 suspend() 去挂起线程的原因,是因为 suspend() 在导致线程暂停的同时,并不会去释放任何锁资源。其他线程都无法访问被它占用的锁。直到对应的线程执行 resume() 方法后,被挂起的线程才能继续,从而其它被阻塞在这个锁的线程才可以继续执行。
3. yield()
使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。只是建议具有相同优先级的其它线程可以运行。
4. 线程融合 join()方法
等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
5. wait() 和 notify()、notifyAll()
wait() 使得线程进入阻塞状态,它有两种形式,一种允许 指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态。 看起来它们与 suspend() 和 resume() 方法对没有什么分别,但是事实上它们是截然不同的。区别的核心在于,这一对方法会释放占用的锁。
这一对方法必须在 synchronized 方法或块中调用。
6. 鎖: 參考 https://hackmd.io/VkwrtobKSzyP2gU6ORQPLw?both#鎖
# multi thread 之間的通信
## 1. 共享記憶體
a. 針對共享變數給予 volatile, 確保共享為新的變數。說明:
http://percent010.blogspot.com/2015/05/volatile-java.html
b. 修改共享變量時使用帶有線程安全、或原子性的物件,或者自己上鎖
## 2. 等待/通知机制
## 3. pip
JDK提供了PipedWriter、 PipedReader、 PipedOutputStream、 PipedInputStream。其中,前面两个是基于字符的,后面两个是基于字节流的
參考: https://redspider.gitbook.io/concurrent/di-yi-pian-ji-chu-pian/5#5.4-guan-dao
## 4. join
使用 concurentA.join()的線程會等待 concurentA結束才繼續往下
## 5. sleep
要提一下的是
a. wait可以指定时间,也可以不指定;而sleep必须指定时间。 不指定時間的wait可能造成
b. wait释放cpu资源,同时释放锁;sleep释放cpu资源,但是不释放锁,所以易死锁。
c. ***wait必须放在同步块或同步方法中***,而sleep可以任意位置
參考: https://redspider.gitbook.io/concurrent/di-yi-pian-ji-chu-pian/5
# 鎖
1. synchronized
2. reentrantLock
synchronized vs reentrantLock:
When using synchronized can meet your needs, use synchronized first, because it is convenient to use, it will automatically release locks, and the performance will be improved after Java 6 optimization. If you want every thread to have a chance to obtain a lock, and you can predict that your system is a typical high concurrency scenario, it is more appropriate to choose ReentrantLock.
This article compares the differences and disadvantages between Synchronized and ReentrantLock, and shares some of my experiences. I hope it can help you understand them. Finally, thank you for reading.
https://medium.com/javarevisited/synchronized-vs-reentrantlock-how-to-choose-cfb5306080e7
# deadlock
suspend() 方法和不指定期限的 wait() 方法都可能产生死锁。 Java 并不在语言级别上支持死锁的避免,我们在编程中必须小心地避免死锁。
參考: https://juejin.cn/post/6951238100945207327
# 問題紀錄
1. pip
a. pip 可以一對多、多對多嗎?
b. pip的阻塞與go有何不同? 發送方也會阻塞? 發送方會有capacity的彈性嗎
2. completableFuture預設的forkjoin線程池使用數量,包含其他的線程併發嗎?還是只計算使用cf的地方的線程數量? 在其他地方已經使用的線程數,會被計入此處的forkjoin嗎
3. Forkjoin 全局線程是怎麼回事,從哪來?只影響cf?
a. Java 7开始引入的一种新Fork/Join线程池https://www.liaoxuefeng.com/wiki/1252599548343744/1306581226487842
5. Executor 任務被開工就減少queue or 完工才減少? 這影響觸發拒絕策略的發生情況
a. 經過測試,只要線程開工就會將task從queue中減少,因此executor的拒絕策略觸發,較為合理可用無需另外在封裝改造 https://github.com/ronnielin8862/java19_practice/blob/main/src/main/java/org/example/freePractice/concucrency/executor/TriggerMaxThreadPool.java
# 細節文章
Java多執行緒(簡潔好文): https://redspider.gitbook.io/concurrent/di-yi-pian-ji-chu-pian/5
Java多執行緒:從基本概念到避坑指南: https://www.gushiciku.cn/pl/gjwJ/zh-tw