This article describes the two concurrent tool classes, semaphore and exchanger.
Semaphore
The Semaphore (English: Semaphore), also known as the Beacon, is a synchronization object that holds a count value between 0 and the specified maximum value. When a thread completes a wait (wait) for the semaphore object at a time, the count is reduced by one, and when the thread finishes releasing the semaphore object once (release), the value is added one. When the count value is 0, the thread waits for the semaphore object to no longer succeed until the semaphore object becomes signaled state. The count value of the semaphore object is greater than 0, the signaled state, and the count value equals 0, which is the nonsignaled state.
The semaphore object is intended to control a shared resource that supports only a limited number of users, and is a method that does not require the use of busy waiting (busy waiting). ----taken from Wikipedia
Semaphore ideas are also used in distributed distribution, and distributed current limiting is a typical case. Now for a small example, use semaphore.
Case
When waiting for a bus, people often need to queue up or squeeze in when they meet a lot.
Solution Solutions
With semaphore initialization of 5 licenses, only 5 players can enter at a time, and when a player exits, other players can enter.
Let's introduce the constructor and some methods of the next semaphore.
Semaphore constructor function
public Semaphore(int permits);public Semaphore(int permits, boolean fair);
The first parameter, permits, represents the number of licenses initialized, and the second parameter indicates whether it is fair.
When using the semaphore (int permits) constructor, the default use of the non-fair
Semaphore Common methods
public void acquire();public void release();
The acquire method obtains a license, and the release method represents a free license.
Note: If you call the release method multiple times, the license is increased. For example, if the initialization license is 0, then two release methods are called, and Semaphore's license becomes 2
These two are the most commonly used methods, and other acquire related methods Tryacquire and acquireuninterruptibly are not introduced here.
Code Player Class
Defines a player class that implements the Runnable interface
public class Player implements Runnable{ private String playerName; private Semaphore semaphore; public Player(String playerName, Semaphore semaphore) { this.playerName = playerName; this.semaphore = semaphore; } @Override public void run() { try { semaphore.acquire(); System.out.println(playerName+"进入,时间:"+LocalTime.now()); Thread.sleep((long) (3000 * Math.random())); } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println(playerName+"退出"); semaphore.release(); } }}
Using the constructor player to pass in the player name and the semaphore object, the Run method first calls the Acquire method to obtain the permission, then the sleep random time, and finally calls the release method to release the license in finally.
Test class
First to use the non-fair look at the effect, the use of unfair is like the usual crowded bus, who first in the car door who advanced. such as (from the network)
Let's take a look at the test code
public static void main(String[] args) throws IOException { Semaphore semaphore = new Semaphore(5); //Semaphore semaphore = new Semaphore(5,true); ExecutorService service = Executors.newCachedThreadPool(); //模拟100个玩家排队 for (int i = 0; i < 100; i++) { service.submit(new Player("玩家"+i,semaphore)); } //关闭线程池 service.shutdown(); //判断线程池是否中断,没有则循环查看当前排队总人数 while (!service.isTerminated()){ System.out.println("当前排队总人数:"+semaphore.getQueueLength()); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } }}
If you want to switch to fair mode simply change the above initialization semaphore to the following code
Semaphore semaphore = new Semaphore(5,true);
Exchanger
Exchanger is primarily used for data exchange between threads. It provides a synchronization point at which two threads can exchange data .
Here is a simple example of two threads exchanging data with each other, and the following exchangerrunnable calls the Exchange method in the Run method to pass its own data over.
public class ExchangerRunnable implements Runnable { private Object data; private String name; private Exchanger exchanger; public ExchangerRunnable(String name, Exchanger exchanger, Object data) { this.exchanger = exchanger; this.name = name; this.data = data; } public void run() { try { Object previous = this.data; this.data = this.exchanger.exchange(previous); System.out.println("名称:" + name + " 之前数据:" + previous + " ,交换之后数据:" + this.data); } catch (InterruptedException e) { e.printStackTrace(); } }}
Next look at the test code
public class Case { private static final Exchanger exchanger = new Exchanger(); private static ExecutorService service = Executors.newFixedThreadPool(2); public static void main(String[] args) { service.submit(new ExchangerRunnable("1", exchanger, "A")); service.submit(new ExchangerRunnable("2", exchanger, "B")); service.shutdown(); }}
Defines a thread pool that contains only two threads, and then creates a class that commits two exchangerrunnable
- When the thread name is 1 of the raw data, a
- When the thread name is 2 raw data, B
Run the test code and you will get the following results
名称:2 之前数据:B ,交换之后数据:A名称:1 之前数据:A ,交换之后数据:B
Case source code Address: Github.com/rainbowda/learnway/tree/master/learnconcurrency/src/main/java/com/learnconcurrency/utils
Welcome to fork, Star, issue and so on, thank you