游戏中超时匹配流程实现 - java

需求:玩家会随机加入游戏,当第一个玩家加入匹配后最多等待时间T,每局游戏固定人数N git代码库:https://gitee.com/ichiva/game_matching.gitjava

匹配接口

package com.company;

import java.util.Collection;
import java.util.Set;

/**
 * 通用匹配
 *
 * @param <T>
 */
public interface Match<T> {
    /**
     * 添加匹配
     * @param ele
     */
    void add(T ele);

    /**
     * 匹配成功
     * @param list
     */
    void success(Collection<T> list);

    /**
     * 匹配失败,未达到固定匹配人数
     * @param list
     */
    void fail(Collection<T> list);
}

超时匹配实现

package com.company;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.*;

/**
 * 超时匹配
 * @param <T>
 */
public abstract class TimeoutMatch<T> extends Thread implements Match<T> {

    /**
     * 匹配超时时间
     */
    private final long timeout;
    private final int capacity;
    private final ExecutorService executorService;
    private final LinkedBlockingDeque<T> deque = new LinkedBlockingDeque<>();

    public TimeoutMatch(int capacity, long timeout){
        this(capacity,timeout,Executors.newSingleThreadExecutor());
    }


    public TimeoutMatch(int capacity, long timeout,ExecutorService executorService){
        this.capacity = capacity;
        this.timeout = timeout;

        this.executorService = executorService;
        start();
    }

    @Override
    public void add(T ele){
        deque.push(ele);
    }

    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()){
            try {
                T start = deque.take();
                System.out.println("匹配开始");

                Future<Set<T>> submit = executorService.submit(new Task(start));
                try {
                    Set<T> list = submit.get(timeout, TimeUnit.SECONDS);
                    success(list);
                }catch (TimeoutException e) {
                    submit.cancel(true);
                }catch (Exception e){
                    e.printStackTrace();
                }

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    private class Task implements Callable<Set<T>>{

        private final T start;

        public Task(T start){
            this.start = start;
        }

        @Override
        public Set<T> call() {
            Set<T> list = new LinkedHashSet<>(capacity);
            list.add(start);
            System.out.println("放入临时匹配队列" + start);

            try {
                while (list.size() != capacity){
                    T ele = deque.take();
                    list.add(ele);
                    System.out.println("放入临时匹配队列" + ele);
                }
            }catch (InterruptedException e) {
                fail(list);
            }

            return list;
        }
    }
}

测试用例

package com.company.test;


import com.company.TimeoutMatch;

import java.util.Collection;
import java.util.UUID;

public class TimeoutMatchTests {

    public static void main(String[] args) throws InterruptedException {

        TestTimeoutMatch match = new TestTimeoutMatch(3,3);

        while (true){
            int num = (int) (Math.random() * 3);
            System.out.printf("加入【%d】人\r\n", num);

            for (int i = 0; i < num; i++) {
                match.add(UUID.randomUUID().toString());
            }

            Thread.sleep(1500);
        }
    }


    static class TestTimeoutMatch extends TimeoutMatch<String> {


        public TestTimeoutMatch(int capacity, long timeout) {
            super(capacity, timeout);
        }

        @Override
        public void success(Collection<String> list) {
            System.out.println("匹配成功");
            for (String item : list) {
                System.out.println("\t" + item);
            }
        }

        @Override
        public void fail(Collection<String> list) {
            System.err.println("匹配失败");
            for (String item : list) {
                System.err.println("\t" + item);
            }
        }
    }
}

测试结果

加入【1】人
匹配开始
放入临时匹配队列865cf9b3-fe43-4b88-89de-cc7c79fb5f84
加入【0】人
加入【1】人
放入临时匹配队列117b966c-d7b0-492d-aff2-cb31bffa207e
匹配失败
	865cf9b3-fe43-4b88-89de-cc7c79fb5f84
	117b966c-d7b0-492d-aff2-cb31bffa207e
加入【1】人
匹配开始
放入临时匹配队列7b944eaa-7e44-4895-8bec-0b3e011fb562
加入【2】人
放入临时匹配队列ac89eec4-5324-490b-a420-a454f59b2220
放入临时匹配队列44feee0c-eafa-4cdc-9223-6a43f5c24782
匹配成功
	7b944eaa-7e44-4895-8bec-0b3e011fb562
	ac89eec4-5324-490b-a420-a454f59b2220
	44feee0c-eafa-4cdc-9223-6a43f5c24782
加入【2】人
匹配开始
放入临时匹配队列a5544b6d-4d22-4eb6-92ed-4bef946f6fa6
放入临时匹配队列69203001-0440-48e5-8247-f8775bc32cad
加入【1】人
放入临时匹配队列55a6dde9-8e82-42da-a3d5-50331ba11664
匹配成功
	a5544b6d-4d22-4eb6-92ed-4bef946f6fa6
	69203001-0440-48e5-8247-f8775bc32cad
	55a6dde9-8e82-42da-a3d5-50331ba11664
加入【2】人
匹配开始
放入临时匹配队列11a6ae84-ba43-495a-af45-87f753424281
放入临时匹配队列37af5d04-e12e-4cf8-8685-738047984051

git代码库:https://gitee.com/ichiva/game_matching.gitgit