A line of Java code to exchange equipment in the game

Posted by Niccaman on Fri, 19 Nov 2021 06:26:23 +0100

Absrtact: since JDK 1.5, the exchange class provided under the JUC package can be used to exchange information between two threads.

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~

Topics: Java Multithreading Game Development