Synchronizer
Solutions are provided for each specific synchronization problem
Semaphore controls access to shared resources through counters.
Test class:
package concurrent; import concurrent.thread.SemaphoreThread; import java.util.concurrent.Semaphore; /** * Take the guest * www.coderknock.com * QQ Group: 213732117 * Creation date: 08/08/2016 * Description: */ public class SemaphoreTest { public static void main(String[] args) { //Declare in Thread that it is not the same object Semaphore semaphore = new Semaphore(3); SemaphoreThread testA = new SemaphoreThread("A", semaphore); SemaphoreThread testB = new SemaphoreThread("B", semaphore); SemaphoreThread testC = new SemaphoreThread("C", semaphore); SemaphoreThread testD = new SemaphoreThread("D", semaphore); SemaphoreThread testE = new SemaphoreThread("E", semaphore); SemaphoreThread testF = new SemaphoreThread("F", semaphore); SemaphoreThread testG = new SemaphoreThread("G", semaphore); testA.start(); testB.start(); testC.start(); testD.start(); testE.start(); testF.start(); testG.start(); } }
Thread Writing:
package concurrent.thread; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.concurrent.Semaphore; /** * Take the guest * www.coderknock.com * QQ Group: 213732117 * Creation date: 08/08/2016 * Description: */ public class SemaphoreThread extends Thread { private static final Logger logger = LogManager.getLogger(SemaphoreThread.class); //Create a semaphore counter with three semaphores public Semaphore semaphore; public SemaphoreThread(String name, Semaphore semaphore) { setName(name); this.semaphore = semaphore; } @Override public void run() { try { logger.debug(getName() + " Waiting for number... " + System.currentTimeMillis()); //Take out a signal semaphore.acquire(); logger.debug(getName() + " Provide services... " + System.currentTimeMillis()); sleep(1000); logger.debug(getName() + " Completion of service... " + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } logger.debug(getName() + " release... " + System.currentTimeMillis()); //Release a signal semaphore.release(); } }
Execution results [Thread name in [] and output after [] of all the following output results]:
[C] - C Number Waiting... 1470642024037 [F] - F Number Waiting... 1470642024036 [E] - E Number Waiting... 1470642024036 [B] - B Number Waiting... 1470642024037 [D] - D Number Waiting... 1470642024037 [A] - A Number Waiting... 1470642023965 [D] - D Provides Services 1470642024039 [C] - C Provides Services 1470642024039 [G] - G Number Waiting... 1470642024036 [F] - F Provides Services 1470642024040 [D] - D Complete Services 1470642025039 [C] - C Complete Services 1470642025039 [D] - D Release 1470642025040 [F] - F Complete Services 1470642025040 [C] - C Release 1470642025041 [B] - B Provides Services 1470642025042 [A] - A Providing Services 1470642025042 [F] - F Release 1470642025043 [E] - E Providing Services 1470642025043 [A] - A Complete Services 1470642026043 [B] - B Complete Services 1470642026043 [B] - B Release 1470642026043 [A] - A Release 1470642026043 [G] - G Provides Services 1470642026044 [E] - E Completion of Services 1470642026045 [E] - E Release 1470642026045 [G] - G Complete Services 1470642027045 [G] - G release... 1470642027046As you can see, after three semaphores have been collected, the thread will block at the receiving position, and will continue to execute only after the semaphores have been released.
CountDownLatchCountDownLatch () calls countDownLatch.await() in the thread to block the process, and continues to execute the remaining content in each thread after a specified number of times have been reached (through countDownLatch.countDown()).
Test class:
package concurrent.thread; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.concurrent.CountDownLatch; /** * Take the guest * www.coderknock.com * QQ Group: 213732117 * Creation date: 08/08/2016 * Description: */ public class package concurrent; import concurrent.thread.CountDownLatchThread; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; /** * Take the guest * www.coderknock.com * QQ Group: 213732117 * Creation date: 08/08/2016 * Description: */ public class CountDownLatchTest { private static final Logger logger = LogManager.getLogger(CountDownLatchTest.class); public static void main(String[] args) throws InterruptedException { //Set trigger when three counts are reached CountDownLatch countDownLatch = new CountDownLatch(3); new CountDownLatchThread("A", countDownLatch).start(); new CountDownLatchThread("B", countDownLatch).start(); new CountDownLatchThread("C", countDownLatch).start(); new CountDownLatchThread("D", countDownLatch).start(); new CountDownLatchThread("E", countDownLatch).start(); for (int i = 3; i > 0; i--) { Thread.sleep(1000); logger.debug(i); countDownLatch.countDown(); } } }
Thread class:
package concurrent.thread; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.concurrent.CountDownLatch; /** * Take the guest * www.coderknock.com * QQ Group: 213732117 * Creation date: 08/08/2016 * Description: */ public class CountDownLatchThread extends Thread { private static final Logger logger = LogManager.getLogger(CountDownLatchThread.class); //Counter private CountDownLatch countDownLatch; public CountDownLatchThread(String name, CountDownLatch countDownLatch) { setName(name); this.countDownLatch = countDownLatch; } @Override public void run() { logger.debug("Execution operation..."); try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } logger.debug("Waiting for the counter to reach the standard..."); try { //Let threads go into blocking state and wait for counts to be released countDownLatch.await(); logger.debug("Enumeration reached, continued execution..."); } catch (InterruptedException e) { e.printStackTrace(); } } }
Implementation results:
[E] - Execution operation... [B] - Execution operation... [A] - Execution operation... [C] - Execution operation... [D] - Execution operation... [main] DEBUG concurrent.CountDownLatchTest - 3 [B] - Waiting for the counter to reach the standard... [E] - Waiting for the counter to reach the standard... [C] - Waiting for the counter to reach the standard... [D] - Waiting for the counter to reach the standard... [A] - Waiting for the counter to reach the standard... [main] DEBUG concurrent.CountDownLatchTest - 2 [main] DEBUG concurrent.CountDownLatchTest - 1 [E] - Enumeration reached, continued execution... [C] - Enumeration reached, continued execution... [B] - Enumeration reached, continued execution... [D] - Enumeration reached, continued execution... [A] - Enumeration reached, continued execution...CyclicBarrier
Cyclic Barrier [Cyclic Cycle, Barrier Barrier Barrier Barrier Barrier Barrier Barrier Barrier Barrier Barrier, Barrier Barrier Barrier Barrier] Cycles wait for the number of blocked threads to reach the specified number, so that the threads participating in the count can continue to execute and execute specific threads (using different constructors can be executed without setting arrival). Other threads
Test class:
package concurrent; import concurrent.thread.CyclicBarrierThread; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.concurrent.CyclicBarrier; /** * Take the guest * www.coderknock.com * QQ Group: 213732117 * Creation date: 08/08/2016 * Description: */ public class CyclicBarrierTest { private static final Logger logger = LogManager.getLogger(CyclicBarrierTest.class); public static void main(String[] args) { //You can use Cyclic Barrier (int parties) to not set what will be executed after arrival CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> { logger.debug("---Enumeration of what is executed after arrival----"); }); new CyclicBarrierThread("A", cyclicBarrier).start(); new CyclicBarrierThread("B", cyclicBarrier).start(); new CyclicBarrierThread("C", cyclicBarrier).start(); new CyclicBarrierThread("D", cyclicBarrier).start(); new CyclicBarrierThread("E", cyclicBarrier).start(); new CyclicBarrierThread("A2", cyclicBarrier).start(); new CyclicBarrierThread("B2", cyclicBarrier).start(); new CyclicBarrierThread("C2", cyclicBarrier).start(); new CyclicBarrierThread("D2", cyclicBarrier).start(); new CyclicBarrierThread("E2", cyclicBarrier).start(); //It should be noted that if the number of threads is not an integer multiple of the number of waiting set above, for example, a thread is added to the program. // When the number of threads reaches 5, only the content of the five threads at the time of arrival will be executed. // The remaining thread will be blocked and the main thread will not be able to exit and the program will not be able to terminate. // New Cyclic Barrier Thread ("F", cyclic Barrier). start (); // / Removing this line of comment will not automatically terminate the program } }
Thread class:
package concurrent.thread; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.Random; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; /** * Take the guest * www.coderknock.com * QQ Group: 213732117 * Creation date: 08/08/2016 * Description: */ public class CyclicBarrierThread extends Thread { private static final Logger logger = LogManager.getLogger(CyclicBarrierThread.class); private CyclicBarrier cyclicBarrier; public CyclicBarrierThread(String name, CyclicBarrier cyclicBarrier) { super(name); this.cyclicBarrier = cyclicBarrier; } @Override public void run() { logger.debug("Execution operation..."); try { int time = new Random().nextInt(10) * 1000; logger.debug("dormancy" + time/1000 + "second"); sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } logger.debug("Waiting for the counter to reach the standard..."); try { //Let threads go into blocking state and wait for counts to be released cyclicBarrier.await(); logger.debug("Enumeration reached, continued execution..."); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }
Implementation results:
[A] - Perform operations... [A] - Sleep for 0 seconds [E2] - Execute operations... [E2] - Hibernate for 5 seconds [D2] - Perform operations... [D2] - Hibernate for 4 seconds [C2] - Perform operations... [C2] - Hibernate for 4 seconds [B2] - Perform operations... [B2] - Sleep for 6 seconds [A2] - Perform operations... [A2] - 8 seconds of dormancy [E] - Perform operations... [E] - Hibernate for 5 seconds [D] - Perform operations... [D] - Sleep for 0 seconds [C] - Perform operations... [C] - Hibernate for 3 seconds [B] - Perform operations... [B] - Sleep for 7 seconds [A] - Waiting for the counter to reach the standard. [D] - Waiting for the counter to reach the standard. [C] - Waiting for the counter to reach the standard. [D2] - Waiting for the counter to reach the standard. [C2] - Waiting for the counter to reach the standard. [C2] DEBUG concurrent. Cyclic Barrier Test - - - what counts to be executed after arrival - - - [C2] - Count reached, continue to execute... [A] - Count reached, continue to execute... [C] - Count reached, continue to execute... [D2] - Count reached, continue to execute... [D] - Count reached, continue to execute... [E2] - Waiting for the counter to reach the standard. [E] - Waiting for the counter to reach the standard. [B2] - Waiting for the counter to reach the standard. [B] - Waiting for the counter to reach the standard. [A2] - Waiting for the counter to reach the standard. [A2] DEBUG concurrent. Cyclic Barrier Test - - - what counts to be executed after arrival - - - [E] - Count reached, continue to execute... [B2] - Count reached, continue to execute... [E2] - Count reached, continue to execute... [B] - Count reached, continue to execute... [A2] - Count reached, continue to execute...It can be imagined that the pattern of long distance bus stops used to be irregular:
Informal long-distance bus stops wait for seats to be full before departure, and then continue to wait and cycle after arriving at the destination. Everyone is a Thread, which triggers cyclic Barrier. await (). When the car is full, it reaches the designated number of arrivals, the vehicle departure is the content of the unified implementation after the arrival, and people on the bus can chat and other operations after the departure. [We temporarily understand that people can not move O() O() after boarding the car.)
CountDownLatch is different from Cyclic Barrier:CountDownLatch is one or more threads that wait for the count to be reached and continue to execute. The await() call does not participate in the count.
Cyclic Barrier is a process in which N threads wait for each other to execute until they reach the zero boundary, while await() calls take part in counting, and Cyclic Barrier performs an action when its support condition is reached, and the process is cyclic.
ExchangerExchanger < T > for data exchange between threads
Test class:
package concurrent; import concurrent.pojo.ExchangerPojo; import concurrent.thread.ExchangerThread; import java.util.HashMap; import java.util.concurrent.Exchanger; /** * Take the guest * www.coderknock.com * QQ Group: 213732117 * Creation date: 08/08/2016 * Description: */ public class ExchangerTest { public static void main(String[] args) { Exchanger<HashMap<String, ExchangerPojo>> exchanger = new Exchanger<>(); new ExchangerThread("A", exchanger).start(); new ExchangerThread("B", exchanger).start(); } }
Entity class:
package concurrent.pojo; import com.alibaba.fastjson.JSON; import java.util.Date; import java.util.List; /** * Take the guest * www.coderknock.com * QQ Group: 213732117 * Creation date: 08/08/2016 * Description: */ public class ExchangerPojo { private int intVal; private String strVal; private List<String> strList; private Date date; public ExchangerPojo(int intVal, String strVal, List<String> strList, Date date) { this.intVal = intVal; this.strVal = strVal; this.strList = strList; this.date = date; } public int getIntVal() { return intVal; } public void setIntVal(int intVal) { this.intVal = intVal; } public String getStrVal() { return strVal; } public void setStrVal(String strVal) { this.strVal = strVal; } public List<String> getStrList() { return strList; } public void setStrList(List<String> strList) { this.strList = strList; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } @Override public String toString() { return JSON.toJSONString(this); } }
Thread class:
package concurrent.thread; import concurrent.pojo.ExchangerPojo; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.*; import java.util.concurrent.Exchanger; /** * Take the guest * www.coderknock.com * QQ Group: 213732117 * Creation date: 08/08/2016 * Description: */ public class ExchangerThread extends Thread { private Exchanger<HashMap<String, ExchangerPojo>> exchanger; private static final Logger logger = LogManager.getLogger(ExchangerThread.class); public ExchangerThread(String name, Exchanger<HashMap<String, ExchangerPojo>> exchanger) { super(name); this.exchanger = exchanger; } @Override public void run() { HashMap<String, ExchangerPojo> map = new HashMap<>(); logger.debug(getName() + "Providers provide data..."); Random random = new Random(); for (int i = 0; i < 3; i++) { int index = random.nextInt(10); List<String> list = new ArrayList<>(); for (int j = 0; j < index; j++) { list.add("list ---> " + j); } ExchangerPojo pojo = new ExchangerPojo(index, getName() + "Data provided", list, new Date()); map.put("The first" + i + "Data", pojo); } try { int time = random.nextInt(10); logger.debug(getName() + "wait for" + time + "second...."); for (int i = time; i > 0; i--) { sleep(1000); logger.debug(getName() + "---->" + i); } //Waiting for exchange is blocked and can interact with another thread many times in one thread, so I won't write it here many times. HashMap<String, ExchangerPojo> getMap = exchanger.exchange(map); time = random.nextInt(10); logger.debug(getName() + "Accept data waiting" + time + "second...."); for (int i = time; i > 0; i--) { sleep(1000); logger.debug(getName() + "---->" + i); } getMap.forEach((x, y) -> { logger.debug(x + " -----> " + y.toString()); }); } catch (InterruptedException e) { e.printStackTrace(); } } }
Implementation results:
[B] - B Providers provide data... [A] - A Providers provide data... [A] - A Wait for 2 seconds..... [B] - B Wait for 0 seconds..... [A] - A---->2 [A] - A---->1 [B] - B Accept data and wait for 1 second.... [A] - A Receive data and wait for 4 seconds.... [B] - B---->1 [A] - A---->4 [B] - Data No. 0 -----> {"date":1470652252049,"intVal":5,"strList":["list ---> 0","list ---> 1","list ---> 2","list ---> 3","list ---> 4"],"strVal":"A Data provided"} [B] - First Data -----> {"date":1470652252049,"intVal":1,"strList":["list ---> 0"],"strVal":"A Data provided"} [B] - Second Data -----> {"date":1470652252049,"intVal":4,"strList":["list ---> 0","list ---> 1","list ---> 2","list ---> 3"],"strVal":"A Data provided"} [A] - A---->3 [A] - A---->2 [A] - A---->1 [A] - Data No. 0 -----> {"date":1470652252057,"intVal":1,"strList":["list ---> 0"],"strVal":"B Data provided"} [A] - First Data -----> {"date":1470652252057,"intVal":6,"strList":["list ---> 0","list ---> 1","list ---> 2","list ---> 3","list ---> 4","list ---> 5"],"strVal":"B Data provided"} [A] - Second Data -----> {"date":1470652252057,"intVal":6,"strList":["list ---> 0","list ---> 1","list ---> 2","list ---> 3","list ---> 4","list ---> 5"],"strVal":"B Data provided"}Phaser
Phaser's personal sense combines CountDownLatch and Cyclic Barrier functions and provides phased capabilities.
Implementing Phased Cyclic Barrier FunctionsTest code:
package concurrent; import concurrent.thread.PhaserThread; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.concurrent.Phaser; /** * Take the guest * Website: www.coderknock.com * QQ Group: 213732117 * Sansan was founded on August 08, 2016 at 21:25:30. */ public class PhaserTest { private static final Logger logger = LogManager.getLogger(PhaserTest.class); public static void main(String[] args) { Phaser phaser = new Phaser() { /**This method has two functions: * 1,When each stage is completed, this method is automatically invoked, so overloading the code written by this method will execute at the end of each stage, which is equivalent to the barrier action of Cyclic Barrier. * 2,When this method returns true, it means that Phaser is terminated, so the return value of this method can be set skillfully to terminate all threads. For example, if this method returns a value of phase >= 3, it means that the program terminates after the entire thread has executed four stages. * */ @Override protected boolean onAdvance(int phase, int registeredParties) { logger.debug("stage--->" + phase); logger.debug("Number of registered threads--->" + registeredParties); return super.onAdvance(phase, registeredParties); } }; for (int i = 3; i > 0; i--) { new PhaserThread("The first" + i + "individual", phaser).start(); } } }
Thread code:
package concurrent.thread; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.Random; import java.util.concurrent.Phaser; /** * Take the guest * Website: www.coderknock.com * QQ Group: 213732117 * Sansan was founded at 21:16:55 on August 08, 2016. */ public class PhaserThread extends Thread { private Phaser phaser; private static final Logger logger = LogManager.getLogger(PhaserThread.class); public PhaserThread(String name, Phaser phaser) { super(name); this.phaser = phaser; //Register the current thread to Phaser this.phaser.register(); logger.debug("name by" + name + "Threads registered" + this.phaser.getRegisteredParties() + "Thread"); } @Override public void run() { logger.debug("Get into..."); phaser.arrive(); for (int i = 6; i > 0; i--) { int time = new Random().nextInt(5); try { logger.debug("sleep" + time + "second"); sleep(time * 1000); if (i == 1) { logger.debug("Number of incomplete threads:" + phaser.getUnarrivedParties()); logger.debug("Last trigger, and cancel itself"); phaser.arriveAndDeregister(); logger.debug("Number of incomplete threads:" + phaser.getUnarrivedParties()); } else { logger.debug("Number of incomplete threads:" + phaser.getUnarrivedParties()); logger.debug(i + "--->Trigger and block..."); phaser.arriveAndAwaitAdvance();//Equivalent to Cyclic Barrier. await (); logger.debug("Number of incomplete threads:" + phaser.getUnarrivedParties()); } } catch (InterruptedException e) { e.printStackTrace(); } } logger.debug("Number of threads registered after logout--->" + phaser.getRegisteredParties()); } }
Implementation results:
[main] - name registers one thread for thread 3 [main] - name registers two threads for the second thread [main] - name registers three threads for the first thread [No. 3] - Enter ____________ [2nd] - Enter... [3rd] - Sleep for 2 seconds [2nd] - Sleep for 1 second [1st] - Enter... [1st] - Stage - > 0 [1st] - Number of registered threads - > 3 [1st] - Sleep for 4 seconds [2nd] - Number of incomplete threads: 3 [2nd] - 6 - > Trigger and block... [3rd] - Number of incomplete threads: 2 [3rd] - 6 - > Trigger and block... [1st] - Number of incomplete threads: 1 [1st] - 6 - > Trigger and block... [1st] - Stage - > 1 [1st] - Number of registered threads - > 3 [1st] - Number of unfinished threads: 3 [3rd] - Number of incomplete threads: 3 [2nd] - Number of incomplete threads: 3 [1st] - Sleep for 1 second [3rd] - Sleep for 0 seconds [2nd] - Sleep for 4 seconds [3rd] - Number of incomplete threads: 3 [3rd] - 5 - > Trigger and block... [1st] - Number of unfinished threads: 2 [1st] - 5 - > Trigger and block... [2nd] - Number of incomplete threads: 1 [2nd] - 5 - > Trigger and block... [2nd] - Stage - > 2 [2nd] - Number of registered threads - > 3 [2nd] - Number of incomplete threads: 3 [3rd] - Number of incomplete threads: 3 [1st] - Number of unfinished threads: 3 [2nd] - Sleep for 0 seconds [3rd] - Sleep for 2 seconds [2nd] - Number of incomplete threads: 3 [1st] - Sleep for 2 seconds [2nd] - 4 - > Trigger and block... [3rd] - Number of incomplete threads: 2 [1st] - Number of unfinished threads: 2 [3rd] - 4 - > Trigger and block... [1st] - 4 - > Trigger and block... [1st] - Stage - > 3 [1st] - Number of registered threads - > 3 [1st] - Number of unfinished threads: 3 [3rd] - Number of incomplete threads: 3 [2nd] - Number of incomplete threads: 3 [1st] - Sleep for 2 seconds [3rd] - Sleep for 1 second [2nd] - Sleep for 4 seconds [3rd] - Number of incomplete threads: 3 [3rd] - 3 - > Trigger and block... [1st] - Number of unfinished threads: 2 [1st] - 3 - > Trigger and block... [2nd] - Number of incomplete threads: 1 [2nd] - 3 - > Trigger and block... [2nd] - Stage - > 4 [2nd] - Number of registered threads - > 3 [2nd] - Number of incomplete threads: 3 [3rd] - Number of incomplete threads: 3 [1st] - Number of unfinished threads: 3 [2nd] - Sleep for 2 seconds [1st] - Sleep for 2 seconds [3rd] - Sleep for 4 seconds [2nd] - Number of incomplete threads: 3 [1st] - Number of unfinished threads: 3 [2nd] - 2 - > Trigger and block... [1st] - 2 - > Trigger and block... [3rd] - Number of incomplete threads: 1 [3rd] - 2 - > Trigger and block... [3rd] - Stage - > 5 [3rd] - Number of registered threads - > 3 [3rd] - Number of incomplete threads: 3 [1st] - Number of unfinished threads: 3 [2nd] - Number of incomplete threads: 3 [3rd] - Sleep for 2 seconds [1st] - Sleep for 3 seconds [2nd] - Sleep for 0 seconds [2nd] - Number of incomplete threads: 3 [2nd] - Last trigger and cancel itself [2nd] - Number of incomplete threads: 2 [Number 2] - Number of threads registered after cancellation - > 2 [3rd] - Number of incomplete threads: 2 [3rd] - Last trigger, and cancel itself [3rd] - Number of incomplete threads: 1 [Number 3] - Number of threads registered after cancellation - > 1 [1st] - Number of incomplete threads: 1 [1st] - Last trigger and cancel itself [1st] - Stage - > 6 [1st] - Number of registered threads - > 0 [1st] - Number of unfinished threads: 0 [1st] - Number of registered threads after cancellation - > 0In the above code, when all threads reach arriveAndAwaitAdvance(), the count is triggered and the thread is blocked, equal to the number of registered threads (that is, when all threads are executed to the agreed place, they are released, so that all threads can continue to execute and trigger onAction events). We can perform different content operations in onAction according to different stages.
Implementing phased CountDownLatch functionalityJust change the above test class as follows:
package concurrent; import concurrent.thread.PhaserThread; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.concurrent.Phaser; import static jodd.util.ThreadUtil.sleep; /** * Take the guest * Website: www.coderknock.com * QQ Group: 213732117 * Sansan was founded on August 08, 2016 at 21:25:30. */ public class PhaserTest { private static final Logger logger = LogManager.getLogger(PhaserTest.class); public static void main(String[] args) { //There are actually three registered threads, but there are no actual threads. int coutNum=3; Phaser phaser = new Phaser(coutNum) { /**This method has two functions: * 1,When each stage is completed, this method is automatically invoked, so overloading the code written by this method will execute at the end of each stage, which is equivalent to the barrier action of Cyclic Barrier. * 2,When this method returns true, it means that Phaser is terminated, so the return value of this method can be set skillfully to terminate all threads. For example, if this method returns a value of phase >= 3, it means that the program terminates after the entire thread has executed four stages. * */ @Override protected boolean onAdvance(int phase, int registeredParties) { logger.debug("stage--->" + phase); logger.debug("Number of registered threads--->" + registeredParties); return registeredParties==coutNum;//When only coutNum threads are left, it means that all the real registered threads have been run and the test can terminate Phaser. } }; for (int i = 3; i > 0; i--) { new PhaserThread("The first" + i + "individual", phaser).start(); } //When phaser is not terminated, the circular registration block can be used for actual business processing. while (!phaser.isTerminated()) { sleep(1000); logger.debug("Trigger once"); phaser.arrive(); //Equivalent to countDownLatch.countDown(); } } }