Java利用 Exchanger 实现游戏中交换装备

目录
  • 1 Exchanger 是什么
  • 2 Exchanger 详解
  • 3 Exchanger 应用

1 Exchanger 是什么

JDK 1.5 开始 JUC 包下提供的 Exchanger 类可用于两个线程之间交换信息。Exchanger 对象可理解为一个包含2个格子的容器,通过调用 exchanger 方法向其中的格子填充信息,当两个格子中的均被填充信息时,自动交换两个格子中的信息,然后将交换的信息返回给调用线程,从而实现两个线程的信息交换。

功能看似简单,但这在某些场景下是很有用处的,例如游戏中两个玩家交换装备;交友软件男女心仪对象匹配。

下面简单模拟下两个玩家交换装备的场景。

package com.chenpi;

import java.util.concurrent.Exchanger;

/**
 * @Description
 * @Author 陈皮
 * @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("屠龙刀");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("交易成功," + Thread.currentThread().getName() + "获得" + str);
    }, "周芷若").start();

    new Thread(() -> {
      String str = null;
      try {
        str = exchanger.exchange("倚天剑");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("交易成功," + Thread.currentThread().getName() + "获得" + str);
    }, "张无忌").start();
  }
}

输出结果如下:

交易成功,张无忌获得屠龙刀
交易成功,周芷若获得倚天剑

2 Exchanger 详解

Exchager 类可用于两个线程之间交换信息,如果一个线程调用了 Exchanger 对象的 exchange 方法之后,会一直阻塞直到另一个线程来和它交换信息,交换之后的信息返回给调用线程,从而实现两个线程的信息交换。

Exchager 底层也是使用到了自旋和 cas 机制。

注意:如果超过两个线程调用同一个 Exchanger 对象 exchange 方法时,结果是不可预计的,只要有2个线程满足条件了,就认为匹配成功并交换信息。而剩下的未能得到配对的线程,则会被阻塞一直等待直到有另一个线程能与它匹配与之配对。

package com.chenpi;

import java.util.concurrent.Exchanger;

/**
 * @Description
 * @Author 陈皮
 * @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("屠龙刀");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("交易成功," + Thread.currentThread().getName() + "获得" + str);
    }, "周芷若").start();

    new Thread(() -> {
      String str = null;
      try {
        str = exchanger.exchange("倚天剑");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("交易成功," + Thread.currentThread().getName() + "获得" + str);
    }, "张无忌").start();

    new Thread(() -> {
      String str = null;
      try {
        str = exchanger.exchange("假的倚天剑");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("交易成功," + Thread.currentThread().getName() + "获得" + str);
    }, "成昆").start();
  }
}

// 输出结果如下
交易成功,周芷若获得假的倚天剑
交易成功,成昆获得屠龙刀

当然,在等待交换信息的线程是可以被中断的,就比如玩家在等待交易过程中,突然玩家下线了,那就应该中断线程等待。

package com.chenpi;

import java.lang.Thread.State;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Exchanger;

/**
 * @Description
 * @Author 陈皮
 * @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("屠龙刀");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("交易成功," + Thread.currentThread().getName() + "获得" + str);
    }, "周芷若");
    threads.add(thread1);

    Thread thread2 = new Thread(() -> {
      String str = null;
      try {
        str = exchanger.exchange("倚天剑");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("交易成功," + Thread.currentThread().getName() + "获得" + str);
    }, "张无忌");
    threads.add(thread2);

    Thread thread3 = new Thread(() -> {
      String str = null;
      try {
        str = exchanger.exchange("假的屠龙刀");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("交易成功," + Thread.currentThread().getName() + "获得" + str);
    }, "成昆");
    threads.add(thread3);

    for (Thread thread : threads) {
      thread.start();
    }

    // 等待5秒
    Thread.sleep(5000);

    for (Thread thread : threads) {
      System.out.println(thread.getName() + ":" + thread.getState());
      // 如果还在阻塞等待则中断线程
      if (thread.getState() == State.WAITING) {
        thread.interrupt();
      }
    }
  }
}

// 输出结果如下
交易成功,张无忌获得屠龙刀
交易成功,周芷若获得倚天剑
周芷若:TERMINATED
张无忌:TERMINATED
成昆:WAITING
交易成功,成昆获得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)

上面演示的是线程如果等不到另一个线程和它交换信息,则会一直等待下去。其实 Exchanger 还可以设置等待指定时间。比如系统设置玩家交换装备匹配时间为60秒,如果超出时间则终止交易。

package com.chenpi;

import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @Description
 * @Author 陈皮
 * @Date 2021/7/11
 * @Version 1.0
 */
public class ChenPiMain {

  public static void main(String[] args) {

    Exchanger<String> exchanger = new Exchanger<>();

    new Thread(() -> {
      try {
        // 超时时间设置为5秒
        String str = exchanger.exchange("屠龙刀", 5, TimeUnit.SECONDS);
        System.out.println("交易成功," + Thread.currentThread().getName() + "获得" + str);
      } catch (TimeoutException e) {
        System.out.println("交易超时!");
        e.printStackTrace();
      } catch (InterruptedException e) {
        System.out.println("交易异常终止");
        e.printStackTrace();
      }
    }, "周芷若").start();
  }
}

// 输出结果如下
交易超时!
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 应用

Exchager 在遗传算法和管道设计等应用中是非常有用的。比如两个线程之间交换缓冲区,填充缓冲区的线程在需要时从另一个线程获得一个刚清空的缓冲区,并将填充的缓冲区传递给清空缓冲区的线程。

package com.chenpi;

import java.awt.image.DataBuffer;
import java.util.concurrent.Exchanger;

/**
 * @Description
 * @Author 陈皮
 * @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();
  }
}

到此这篇关于Java利用 Exchanger 实现游戏中交换装备的文章就介绍到这了,更多相关Java利用 Exchanger 实现交换装备内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java多线程编程之使用Exchanger数据交换实例

    用于实现两个人之间的数据交换,每个人在完成一定的事务后想与对方交换数据,第一个先拿出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据. 复制代码 代码如下: package com.ljq.test.thread;   import java.util.concurrent.Exchanger; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;   public cla

  • Java编程线程同步工具Exchanger的使用实例解析

    本文研究的主要是Java编程线程同步工具Exchanger的使用,下面看看具体内容. 如果两个线程在运行过程中需要交换彼此的信息,比如一个数据或者使用的空间,就需要用到Exchanger这个类,Exchanger为线程交换信息提供了非常方便的途径,它可以作为两个线程交换对象的同步点,只有当每个线程都在进入 exchange ()方法并给出对象时,才能接受其他线程返回时给出的对象. 每次只能两个线程交换数据,如果有多个线程,也只有两个能交换数据.下面看个通俗的例子:一手交钱一首交货! public

  • Java并发工具类Exchanger的相关知识总结

    一.Exchanger的理解 Exchanger 属于java.util.concurrent包: Exchanger 是 JDK 1.5 开始提供的一个用于两个工作线程之间交换数据的封装工具类; 一个线程在完成一定的事务后想与另一个线程交换数据,则第一个先拿出数据的线程会一直等待第二个线程,直到第二个线程拿着数据到来时才能彼此交换对应数据. 二.Exchanger类中常用方法 public Exchanger() 无参构造方法.表示创建一个新的交换器. public V exchange(V

  • Java并发编程之Exchanger方法详解

    简介 Exchanger是一个用于线程间数据交换的工具类,它提供一个公共点,在这个公共点,两个线程可以交换彼此的数据. 当一个线程调用exchange方法后将进入等待状态,直到另外一个线程调用exchange方法,双方完成数据交换后继续执行. Exchanger的使用 方法介绍 exchange(V x):阻塞当前线程,直到另外一个线程调用exchange方法或者当前线程被中断. x : 需要交换的对象. exchange(V x, long timeout, TimeUnit unit):阻塞

  • Java Exchanger并发类使用方法

    简介 Exchanger是java 5引入的并发类,Exchanger顾名思义就是用来做交换的.这里主要是两个线程之间交换持有的对象.当Exchanger在一个线程中调用exchange方法之后,会等待另外的线程调用同样的exchange方法. 两个线程都调用exchange方法之后,传入的参数就会交换. 类定义 public class Exchanger<V> 其中V表示需要交换的对象类型. 类继承 java.lang.Object ↳ java.util.concurrent.Excha

  • 解析Java并发Exchanger的使用

    类定义 public class Exchanger<V> 其中V表示需要交换的对象类型. 类继承 java.lang.Object java.util.concurrent.Exchanger<V> Exchanger直接继承自Object. 构造函数 Exchanger()  Exchanger提供一个无参构造函数. 两个主要方法 1.public V exchange(V x) throws InterruptedException 当这个方法被调用的时候,当前线程将会等待直

  • 通俗易懂学习java并发工具类-Semaphore,Exchanger

    1. 控制资源并发访问--Semaphore Semaphore可以理解为信号量,用于控制资源能够被并发访问的线程数量,以保证多个线程能够合理的使用特定资源. Semaphore就相当于一个许可证,线程需要先通过acquire方法获取该许可证,该线程才能继续往下执行,否则只能在该方法出阻塞等待.当执行完业务功能后,需要通过release()方法将许可证归还,以便其他线程能够获得许可证继续执行. Semaphore可以用于做流量控制,特别是公共资源有限的应用场景,比如数据库连接.假如有多个线程读取

  • Java利用 Exchanger 实现游戏中交换装备

    目录 1 Exchanger 是什么 2 Exchanger 详解 3 Exchanger 应用 1 Exchanger 是什么 JDK 1.5 开始 JUC 包下提供的 Exchanger 类可用于两个线程之间交换信息.Exchanger 对象可理解为一个包含2个格子的容器,通过调用 exchanger 方法向其中的格子填充信息,当两个格子中的均被填充信息时,自动交换两个格子中的信息,然后将交换的信息返回给调用线程,从而实现两个线程的信息交换. 功能看似简单,但这在某些场景下是很有用处的,例如

  • java利用htmlparser获取html中想要的代码具体实现

    这两天需要做一些东西,需要抓取别人网页中的一些信息.最后用htmlparser来解析html. 直接从代码中看吧: 首先需要注意导入包为:import org.htmlparser下面的包 复制代码 代码如下: List<Mp3> mp3List = new ArrayList<Mp3>();        try{            Parser parser = new Parser(htmlStr);//初始化Parser,这里要注意导入包为org.htmlparser.

  • Java 使用poi把数据库中数据导入Excel的解决方法

    Java 利用poi把数据库中数据导入Excel 效果: 使用时先把poi包导入工程的path,注意只需要导入poi包即可,下载后有三个jar包 核心代码: 连接数据库:DBConnection.java 复制代码 代码如下: package org.xg.db;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;i

  • Java并发编程之代码实现两玩家交换装备

    目录 1 Exchanger 是什么 2 Exchanger 详解 3 Exchanger 应用 总结 1 Exchanger 是什么 JDK 1.5 开始 JUC 包下提供的 Exchanger 类可用于两个线程之间交换信息.Exchanger 对象可理解为一个包含2个格子的容器,通过调用 exchanger 方法向其中的格子填充信息,当两个格子中的均被填充信息时,自动交换两个格子中的信息,然后将交换的信息返回给调用线程,从而实现两个线程的信息交换. 功能看似简单,但这在某些场景下是很有用处的

  • Java利用剪贴板实现交换程序间数据的方法

    本文实例讲述了Java利用剪贴板交换程序间数据的实现方法.在图形化系统中,系统剪贴板非常重要,很难想象一个没有剪贴板功能的图形化操作系统使用起来会是怎样.本例就实现了Java 程序与所在系统的剪贴板的数据交流,当单击"Paste"按钮后,Java 程序从系统剪贴板中取得数据并显示在一个JTextArea 组件中:当单击"Copy"按钮后,文本区中的选中文本将被传送到系统剪贴板上. 首先必须得到系统剪贴板的实例引用,java.awt.Toolkit 类中提供了getS

  • Java 在游戏中探索数组二维数组

    目录 什么是数组 举例(装备栏) 声明数组 int类型 String类型 数组操作 遍历数组 二维数组 声明二维数组 这里是JAVA成仙路,关注我学习JAVA不迷路 什么是数组 数组(Array)是有序的元素序列. 若将有限个类型相同的变量的集合命名,那么这个名称为数组名.组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量/12713827).用于区分数组的各个元素的数字编号称为下标.数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式.

  • Java 在游戏中探索数组二维数组

    目录 什么是数组 举例(装备栏) 声明数组 int类型 String类型 数组操作 遍历数组 二维数组 声明二维数组 什么是数组 数组(Array)是有序的元素序列. 若将有限个类型相同的变量的集合命名,那么这个名称为数组名.组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量/12713827).用于区分数组的各个元素的数字编号称为下标.数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式. 这些有序排列的同类数据元素的集合称为数组. 数

  • Java利用深度搜索解决数独游戏详解

    目录 一.问题描述 二.输入和输出 三.输入和输出样例 四.分析 五.算法设计 六.代码 七.测试 一.问题描述 数独是一项非常简单的任务.如下图所示,一张 9 行 9 列的表被分成 9 个 3*3 的小方格.在一些单元格中写上十进制数字 1~9,其他单元格为空.目标是用 1 ~9 的数字填充空单元格,每个单元格一个数字,这样在每行.每列和每个被标记为 3*3 的子正方形内,所有 1~9 的数字都会出现.编写一个程序来解决给定的数独任务. 二.输入和输出 1.输入 对于每个测试用例,后面都跟 9

  • 利用Java设置Word文本框中的文字旋转方向的实现方法

    Java设置Word文本框中的文字旋转方向 本次程序测试环境如下: Word测试文档版本:.docx 2013 Word Jar包工具:free spire.doc.jar 3.9.0 代码编译工具:IDEA Jdk版本:1.8.0 导入操作文档所需的jar包工具,如图结果: Java import com.spire.doc.*; import com.spire.doc.documents.*; import com.spire.doc.fields.TextBox; import com.

  • Java利用Map实现计算文本中字符个数

    目录 一.题目要求 二.分析 三.部分代码展示 四.全部代码 五.结果截图(部分) 六.a.txt文本 一.题目要求 有一个英文的文本文档a.txt , 需要读取该文本文档并计算文档中英文字符出现的次数,最后打印输出 注意:map集合只能放入英文字符,不能够有空格数字引号等字符,所以在写代码的时候需要额外的进行判断,还需要考虑的一点是英文字符是有大小写的,但是统计在map里面就不区分大小写 二.分析 1.需要先获取文档的路径,并创建HashMap作为存放次数的容器,key的类型为Characte

随机推荐