Java Concurrent Programming Code Realization of Two Players Exchange Equipment

  • 2021-11-13 07:36:45
  • OfStack

Directory 1 What is Exchanger 2 Exchanger Detailed Explanation 3 Exchanger Application Summary

1 What is Exchanger

The Exchanger class provided under the JUC package starting with JDK 1.5 can be used to exchange information between two threads. Exchanger object can be understood as a container containing two grids. By calling exchanger method, the grids are filled with information. When both grids are filled with information, the information in the two grids is automatically exchanged, and then the exchanged information is returned to the calling thread, thus realizing 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 male and female favorite objects.

The following is a simple simulation of the next two players exchanging equipment.


package com.chenpi;
import java.util.concurrent.Exchanger;
/**
 * @Description
 * @Author  Pericarpium tangerinae 
 * @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 Slayer ");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(" The transaction was successful, " + Thread.currentThread().getName() + " Obtain " + str);
    }, " Zhou Zhiruo ").start();
    new Thread(() -> {
      String str = null;
      try {
        str = exchanger.exchange(" Heaven-leaning Sword ");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(" The transaction was successful, " + Thread.currentThread().getName() + " Obtain " + str);
    }, " Zhang Wuji ").start();
  }
}

//The output is as follows
The transaction was successful and Zhang Wuji won Tu Longdao
The transaction was successful, and Zhou Zhiruo won the sword of relying on heaven

2 Exchanger Detailed Explanation

The Exchager class can be used to exchange information between two threads. If one thread calls the exchange method of the Exchanger object, it will block until the other thread exchanges information with it, and the exchanged information will be returned to the calling thread, thus realizing the information exchange between the two threads.

Spin and cas mechanisms are also used in the bottom layer of Exchager.

Note that if more than two threads call the exchange method of the same Exchanger object, the result is unpredictable. As long as two threads meet the conditions, the match is considered successful and information is exchanged. The remaining threads that fail to be paired will be blocked for 1 until another thread can match and pair with it.


package com.chenpi;
import java.util.concurrent.Exchanger;
/**
 * @Description
 * @Author  Pericarpium tangerinae 
 * @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 Slayer ");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(" The transaction was successful, " + Thread.currentThread().getName() + " Obtain " + str);
    }, " Zhou Zhiruo ").start();
    new Thread(() -> {
      String str = null;
      try {
        str = exchanger.exchange(" Heaven-leaning Sword ");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(" The transaction was successful, " + Thread.currentThread().getName() + " Obtain " + str);
    }, " Zhang Wuji ").start();
    new Thread(() -> {
      String str = null;
      try {
        str = exchanger.exchange(" Fake Heaven-leaning Sword ");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(" The transaction was successful, " + Thread.currentThread().getName() + " Obtain " + str);
    }, " Cheng Kun ").start();
  }
}

//The output is as follows
The transaction was successful, and Zhou Zhiruo got a fake sword of relying on heaven
The transaction was successful and Cheng Kun won the Tu Longdao

Of course, the thread waiting to exchange information can be interrupted. For example, when the player suddenly goes offline while waiting for the transaction, the thread 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  Pericarpium tangerinae 
 * @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 Slayer ");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(" The transaction was successful, " + Thread.currentThread().getName() + " Obtain " + str);
    }, " Zhou Zhiruo ");
    threads.add(thread1);
    Thread thread2 = new Thread(() -> {
      String str = null;
      try {
        str = exchanger.exchange(" Heaven-leaning Sword ");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(" The transaction was successful, " + Thread.currentThread().getName() + " Obtain " + str);
    }, " Zhang Wuji ");
    threads.add(thread2);
    Thread thread3 = new Thread(() -> {
      String str = null;
      try {
        str = exchanger.exchange(" Fake Dragon Slayer ");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(" The transaction was successful, " + Thread.currentThread().getName() + " Obtain " + str);
    }, " Cheng Kun ");
    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());
      //  Break the thread if it is still blocking and waiting 
      if (thread.getState() == State.WAITING) {
        thread.interrupt();
      }
    }
  }
}

//The output is as follows
The transaction was successful and Zhang Wuji won Tu Longdao
The transaction was successful, and Zhou Zhiruo won the sword of relying on heaven
Zhou Zhiruo: TERMINATED
Zhang Wuji: TERMINATED
Cheng Kun: 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)

What is shown above is that if a thread can't wait for another thread to exchange information with it, it will wait for 1. In fact, Exchanger can also set a waiting time. For example, the system sets the matching time for players to exchange equipment to 60 seconds, and if it exceeds the time, 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  Pericarpium tangerinae 
 * @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 Slayer ", 5, TimeUnit.SECONDS);
        System.out.println(" The transaction was successful, " + Thread.currentThread().getName() + " Obtain " + str);
      } catch (TimeoutException e) {
        System.out.println(" Trading timeout! ");
        e.printStackTrace();
      } catch (InterruptedException e) {
        System.out.println(" Abnormal termination of transaction ");
        e.printStackTrace();
      }
    }, " Zhou Zhiruo ").start();
  }
}

//The output is as follows
Trading 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 Exchanger application

Exchager is very useful in applications such as genetic algorithms and pipeline design. For example, when two threads exchange buffers, the thread that fills the buffer gets 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  Pericarpium tangerinae 
 * @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();
  }
}

Summarize


Related articles: