使用JS呼叫瀏覽器的列印功能
在Java中,從JDK1.5後開始引入併發程式設計序相關的內容,為進一步理解和編寫更加高效的應用程式,從java.util.concurrent包下開始瞭解,對應的併發程式設計的相關的類。
CountDownLatch類的相關的理解和對應的程式demo編寫理解。藉助的工具是Idea,首先檢視到對應的點就是,併發百年城所在的包。
CountDownLatch在java.util.concurrent包下,主要作用是等待執行緒全部執行完成後,再繼續執行下面的操作。使用的業務場景可能是:如在某一執行緒處理某種業務邏輯前,需要有其他執行緒的相關資料的先執行初始化,其他執行緒執行完成後才能執行該執行緒的處理業務邏輯;保證其在執行業務邏輯時的正確性。可以參考下方的執行圖,在執行使用者執行緒A的時候,需要等待A、B、C、D執行緒執行完對應的業務處理,才能夠執行使用者執行緒A。在這種業務場景下可使用CountDownLatch類來完成對應的執行流程。
對應的使用程式碼的Demo如下:
public class CountDownLatchTest { private static CountDownLatch cdl = new CountDownLatch(4); public static void main(String[] args) throws InterruptedException { UserRunnable userRunnable = new UserRunnable(); userRunnable.setL(2000); UserRunnable u1= new UserRunnable(); u1.setL(4000); UserRunnable u2 = new UserRunnable(); u2.setL(10000); UserRunnable u3 = new UserRunnable(); u3.setL(15000); new Thread(userRunnable).start(); new Thread(u1).start(); new Thread(u2).start(); new Thread(u3).start(); cdl.await(); System.out.println("主執行緒任務執行結束!"); } static class UserRunnable implements Runnable { private long l; public UserRunnable() {} public long getL() { return l; } public void setL(long l) { this.l = l; } public UserRunnable(long l) { this.l = l; } @Override public void run() { try { System.out.println(l+"==============1=============="+System.currentTimeMillis()); Thread.sleep(l); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(l+"==============2=============="+System.currentTimeMillis()); cdl.countDown(); } } }
在編寫完對應的程式碼後,執行結果如下:
4000==============1==============1624342340360
10000==============1==============1624342340361
15000==============1==============1624342340362
2000==============1==============1624342340366
2000==============2==============1624342342403
4000==============2==============1624342344364
10000==============2==============1624342350376
15000==============2==============1624342355374
主執行緒任務執行結束!
在上方執行的結果可以知道,我們等待四個子執行緒執行完對應的任務後才開始繼續執行對應的執行緒。當我們的子執行緒和我們對應的填寫的new CountDownLatch(1);中的從4變更為1時,表示只要有一個任務執行完成即可繼續執行對應的執行緒工作。
private static CountDownLatch cdl = new CountDownLatch(1);
更改為1後執行的結果如下:
4000==============1==============1624342483910
10000==============1==============1624342483912
15000==============1==============1624342483912
2000==============1==============1624342483913
2000==============2==============1624342485917
主執行緒任務執行結束!
4000==============2==============1624342487918
10000==============2==============1624342493916
15000==============2==============1624342498916
在學習CountDownLatch時,關注其實現中的主要幾個方法,能夠更加快速理解其設計的原理以及應用的業務場景
public CountDownLatch(int count);
public void await();
public boolean await(long timeout, TimeUnit unit);
public void countDown();
其中,主要的設計思想方法在其內部類方法Sync上,底層基於AQS機制,保證了在多執行緒下的相關的操作。
private static final class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 4982264981922014374L; Sync(int count) { setState(count); } int getCount() { return getState(); }
//嘗試去釋放 protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; } //迴圈,當對應的數值為0則推出迴圈 protected boolean tryReleaseShared(int releases) { for (;;) { int c = getState(); if (c == 0) return false; int nextc = c-1; if (compareAndSetState(c, nextc)) return nextc == 0; } } }