Details of auxiliary classes in JUC:
-
CountDownLatch: suppose you are a librarian in such a scenario. Now there are five people in the library. How can you guarantee to lock the door when all five people are gone
-
Use multithreading to simulate code demonstration:
public class TestThread1 { public static void main(String[] args) throws InterruptedException { lockDoor(); } private static void lockDoor() { for (int i = 0; i < 5; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + "\t" + "After reading, I went out of the library"); }, String.valueOf(i)).start(); } System.out.println("I'm the librarian. I'll lock the door!!!!"); } }
Unfortunately, the use of the above code can not meet the requirements of the topic may lock the reader in the library!
-
The solution is to use CountDownLatch to solve the code demonstration:
private static void countDownLatchTest() throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(5); for (int i = 0; i < 5; i++) { new Thread(() ->{ System.out.println(Thread.currentThread().getName()+"\t"+"After reading, I went out of the library"); // Someone went out of the library, count down one countDownLatch.countDown(); },String.valueOf(i)).start(); } // I'm waiting at the door to find out that there are no people in the library. I'm locking the door countDownLatch.await(); System.out.println("I'm the librarian. I'll lock the door!!!!"); }
-
Principle:
- CountDownLatch has two main methods, which block when one or more threads call the await method.
- Other threads calling the countDown method will reduce the counter by 1 (the thread calling the countDown method will not block),
- When the value of the counter changes to 0, the thread blocked by the await method will wake up and continue to execute.
-
- CyclicBarrier: after you lock the door and leave the class, you invite some friends to have dinner. Some people arrive early, some people arrive on time, and only when they are together can they start eating:
- Solution: CyclicBarrier
private static void cyclicBarrierTest(){ CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () ->{ // People eat together System.out.println("ok Start to eat "); }); for (int i = 0; i < 5; i++) { new Thread(()->{ System.out.println(Thread.currentThread().getName()+"Here we are!"); try { // When people are not together, they just wait cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }, String.valueOf(i)).start(); } }
- How to use CyclicBarrier:
- It literally means a Barrier that can be used in a Cyclic way. What it has to do is:
- Let a group of threads get blocked when they reach a barrier (also called a synchronization point),
- The barrier will not open until the last thread reaches the barrier
- After opening the door, all threads blocked by the barrier will continue to work
- Thread enters the barrier through the await() method of CyclicBarrier
- It literally means a Barrier that can be used in a Cyclic way. What it has to do is:
- The difference between CyclicBarrier and CountDownLatch:
- CountDownLatch is disposable and CyclicBarrier is recyclable
- The responsibilities of CountDownLatch participating threads are different, some are counting down, some are waiting for the countdown to end. The responsibilities of the threads that CyclicBarrier participates in are the same
- Solution: CyclicBarrier
- Because the last time you locked the door, the librarian gave you a bigger task: to help others find parking spaces in the parking lot:
-
Solution: Semaphore
private static void semaphoreTest() { // There are only three parking spaces Semaphore semaphore = new Semaphore(3); // Now there are six cars for (int i = 0; i < 6; i++) { new Thread(()->{ try { semaphore.acquire(); System.out.println(Thread.currentThread().getName()+"\t Occupied a parking space"); // Time to occupy parking space TimeUnit.SECONDS.sleep(new Random().nextInt(3) + 1); System.out.println(Thread.currentThread().getName()+"\t It's gone! It's gone!"); } catch (InterruptedException e) { e.printStackTrace(); }finally { semaphore.release(); } }).start(); } }
-
Principle of use:
-
In terms of semaphores, we define two operations / METHODS:
- Acquire when a thread calls the acquire operation, it either obtains the semaphore successfully (semaphore minus 1), or waits until a thread releases the semaphore or times out.
- release actually adds 1 to the semaphore value and wakes up the waiting thread.
-
Semaphores are mainly used for two purposes: one is for mutually exclusive use of multiple shared resources, and the other is for the control of the number of concurrent threads.
-
-
Published 110 original articles · praised 8 · visited 5260