--- 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