This article is shared from Huawei cloud community< One line of Java code enables two players to exchange equipment [concurrent programming] >, author: JavaLib of Chen PI.
1 what is exchange
Since JDK 1.5, the exchange class provided under the JUC package can be used to exchange information between two threads. The exchange object can be understood as a container containing two lattices. It fills the lattices with information by calling the exchange method. When both lattices are filled with information, the information in the two lattices is automatically exchanged, and then the exchanged information is returned to the calling thread, so as to realize the information exchange between the two threads.
The function seems simple, but it is very useful in some scenarios, such as exchanging equipment between two players in the game; Dating software matches men's and women's favorite objects.
The following is a simple simulation of the scene where two players exchange equipment.
package com.chenpi; import java.util.concurrent.Exchanger; /** * @Description * @Author dried tangerine peel * @Date 2021/7/11 * @Version 1.0 */ public class ChenPiMain { public static void main(String[] args) throws InterruptedException { Exchanger<String> exchanger = new Exchanger<>(); new Thread(() -> { String str = null; try { str = exchanger.exchange("Dragon slaying knife"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Successful trade," + Thread.currentThread().getName() + "get" + str); }, "Zhou Zhiruo").start(); new Thread(() -> { String str = null; try { str = exchanger.exchange("Heaven reliant sword"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Successful trade," + Thread.currentThread().getName() + "get" + str); }, "zhang wuji").start(); } } // The output results are as follows After the successful transaction, Zhang Wuji obtained the Dragon butcher's knife If the transaction is successful, Zhou Zhiruo obtains the heaven reliant sword
2 detailed explanation of exchange
The Exchanger class can be used to exchange information between two threads. If a thread calls the exchange method of the exchange object, it will block until another thread exchanges information with it. The exchanged information is returned to the calling thread, so as to realize the information exchange between the two threads.
The bottom layer of Exchager also uses spin and cas mechanisms.
Note that if more than two threads call the exchange method of the same exchange object, the result is unpredictable. As long as two threads meet the conditions, the matching is considered successful and information is exchanged. The remaining threads that cannot be paired will be blocked and wait until another thread can match it.
package com.chenpi; import java.util.concurrent.Exchanger; /** * @Description * @Author dried tangerine peel * @Date 2021/7/11 * @Version 1.0 */ public class ChenPiMain { public static void main(String[] args) { Exchanger<String> exchanger = new Exchanger<>(); new Thread(() -> { String str = null; try { str = exchanger.exchange("Dragon slaying knife"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Successful trade," + Thread.currentThread().getName() + "get" + str); }, "Zhou Zhiruo").start(); new Thread(() -> { String str = null; try { str = exchanger.exchange("Heaven reliant sword"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Successful trade," + Thread.currentThread().getName() + "get" + str); }, "zhang wuji").start(); new Thread(() -> { String str = null; try { str = exchanger.exchange("Fake heaven reliant sword"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Successful trade," + Thread.currentThread().getName() + "get" + str); }, "Quint ").start(); } } // The output results are as follows If the transaction is successful, Zhou Zhiruo obtains a fake heaven reliant sword The transaction was successful, and Cheng Kun obtained the Dragon butcher's knife
Of course, the thread waiting for information exchange can be interrupted. For example, when a player suddenly goes offline while waiting for a transaction, the thread waiting should be interrupted.
package com.chenpi; import java.lang.Thread.State; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Exchanger; /** * @Description * @Author dried tangerine peel * @Date 2021/7/11 * @Version 1.0 */ public class ChenPiMain { public static void main(String[] args) throws InterruptedException { Exchanger<String> exchanger = new Exchanger<>(); List<Thread> threads = new ArrayList<>(3); Thread thread1 = new Thread(() -> { String str = null; try { str = exchanger.exchange("Dragon slaying knife"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Successful trade," + Thread.currentThread().getName() + "get" + str); }, "Zhou Zhiruo"); threads.add(thread1); Thread thread2 = new Thread(() -> { String str = null; try { str = exchanger.exchange("Heaven reliant sword"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Successful trade," + Thread.currentThread().getName() + "get" + str); }, "zhang wuji"); threads.add(thread2); Thread thread3 = new Thread(() -> { String str = null; try { str = exchanger.exchange("Fake dragon slaying knife"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Successful trade," + Thread.currentThread().getName() + "get" + str); }, "Quint "); threads.add(thread3); for (Thread thread : threads) { thread.start(); } // Wait 5 seconds Thread.sleep(5000); for (Thread thread : threads) { System.out.println(thread.getName() + ":" + thread.getState()); // Interrupt the thread if it is still blocking and waiting if (thread.getState() == State.WAITING) { thread.interrupt(); } } } } // The output results are as follows After the successful transaction, Zhang Wuji obtained the Dragon butcher's knife If the transaction is successful, Zhou Zhiruo obtains the heaven reliant sword Zhou Zhiruo:TERMINATED zhang wuji:TERMINATED Quint :WAITING The transaction was successful, and Cheng Kun won null java.lang.InterruptedException at java.util.concurrent.Exchanger.exchange(Exchanger.java:568) at com.chenpi.ChenPiMain.lambda$main$2(ChenPiMain.java:47) at java.lang.Thread.run(Thread.java:748)
The above shows that if a thread cannot wait for another thread to exchange information with it, it will wait all the time. In fact, exchange can also set the waiting time. For example, the system sets the matching time for players to exchange equipment to 60 seconds. If the time is exceeded, the transaction will be terminated.
package com.chenpi; import java.util.concurrent.Exchanger; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * @Description * @Author dried tangerine peel * @Date 2021/7/11 * @Version 1.0 */ public class ChenPiMain { public static void main(String[] args) { Exchanger<String> exchanger = new Exchanger<>(); new Thread(() -> { try { // The timeout is set to 5 seconds String str = exchanger.exchange("Dragon slaying knife", 5, TimeUnit.SECONDS); System.out.println("Successful trade," + Thread.currentThread().getName() + "get" + str); } catch (TimeoutException e) { System.out.println("Transaction timeout!"); e.printStackTrace(); } catch (InterruptedException e) { System.out.println("Abnormal termination of transaction"); e.printStackTrace(); } }, "Zhou Zhiruo").start(); } } // The output results are as follows Transaction timeout! java.util.concurrent.TimeoutException at java.util.concurrent.Exchanger.exchange(Exchanger.java:626) at com.chenpi.ChenPiMain.lambda$main$0(ChenPiMain.java:22) at java.lang.Thread.run(Thread.java:748)
3. Exchange application
Exchager is very useful in applications such as genetic algorithm and pipeline design. For example, two threads exchange buffers. The thread that fills the buffer obtains a newly emptied buffer from another thread when necessary, and passes the filled buffer to the thread that empties the buffer.
package com.chenpi; import java.awt.image.DataBuffer; import java.util.concurrent.Exchanger; /** * @Description * @Author dried tangerine peel * @Date 2021/7/11 * @Version 1.0 */ public class ChenPiMain { Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>(); DataBuffer initialEmptyBuffer = ... a made-up type DataBuffer initialFullBuffer = ... class FillingLoop implements Runnable { public void run() { DataBuffer currentBuffer = initialEmptyBuffer; try { while (currentBuffer != null) { addToBuffer(currentBuffer); if (currentBuffer.isFull()) { currentBuffer = exchanger.exchange(currentBuffer); } } } catch (InterruptedException ex) { ...handle ...} } } class EmptyingLoop implements Runnable { public void run() { DataBuffer currentBuffer = initialFullBuffer; try { while (currentBuffer != null) { takeFromBuffer(currentBuffer); if (currentBuffer.isEmpty()) { currentBuffer = exchanger.exchange(currentBuffer); } } } catch (InterruptedException ex) { ...handle ...} } } void start() { new Thread(new FillingLoop()).start(); new Thread(new EmptyingLoop()).start(); } }
Click focus to learn about Huawei cloud's new technologies for the first time~