模擬可併發的棋牌遊戲業務邏輯處理

背景:

之前爲了簡單,一直使用Node.js寫遊戲服務器,經過不斷的探索研究,發現對於現代多核心CPU,顯然是Java這種多線程支持的語言更適合寫遊戲服務器,使得多核CPU利用率高很多。

測試如下:

package com.mmall.mytest;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*
一個桌子
 */
class Room {
    Random random = new Random();
    // 輪到第幾個人出牌了
    private int nTurnTo = 0;

    // 房間號
    int roomId = 0;

    Room(int roomId) {
        this.roomId = roomId;
    }

    // 執行出牌操作
    public void exec(int index) {
        // 使得房間一次性只能處理一條消息(實際上也不可能一個房間多個人併發的發消息)
        synchronized (this) {
            if (index == nTurnTo) {
                // 模擬複雜任務的計算過程
                try {
                    Thread.sleep(random.nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("房間號:" + roomId + " 第" + nTurnTo + "個人出牌完畢");
                nTurnTo++;
                nTurnTo %= 4;
            }
        }
    }
}

/**
 * 模擬某一個房間中一個人出牌動作,被封裝成一個任務
 */
class Task implements Runnable {
    // 第幾個人出牌
    int i;

    // 所在的房間
    Room room;

    Task(int i, Room room) {
        this.i = i;
        this.room = room;
    }

    @Override
    public void run() {
        this.room.exec(i);
    }
}

/**
 * 模擬併發執行Netty中NIO線程收到的任務
 */
public class Main2 {
    // 業務線程池
    static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 50);

    // 模擬隨機一個人出牌,但是鬥地主必須是0-1-2-3-0...這樣順序出牌,從而驗證服務器端可以對其中一個房間鎖住,保證順序出牌
    static Random random = new Random();

    // 10個房間
    static Room room = new Room(0);
    static Room room1 = new Room(1);
    static Room room2 = new Room(2);
    static Room room3 = new Room(3);
    static Room room4 = new Room(4);
    static Room room5 = new Room(5);
    static Room room6 = new Room(6);
    static Room room7 = new Room(7);
    static Room room8 = new Room(8);
    static Room room9 = new Room(9);


    public static void main(String[] args) {
        // 模擬每個房間隨機30次出牌
        for (int i = 0; i < 30; i++) {
            executorService.submit(new Task(random.nextInt(4), room));
            executorService.submit(new Task(random.nextInt(4), room1));
            executorService.submit(new Task(random.nextInt(4), room2));
            executorService.submit(new Task(random.nextInt(4), room3));
            executorService.submit(new Task(random.nextInt(4), room4));
            executorService.submit(new Task(random.nextInt(4), room5));
            executorService.submit(new Task(random.nextInt(4), room6));
            executorService.submit(new Task(random.nextInt(4), room7));
            executorService.submit(new Task(random.nextInt(4), room8));
            executorService.submit(new Task(random.nextInt(4), room9));
        }

        executorService.shutdown();
    }
}

/*
房間號:2 第0個人出牌完畢
房間號:9 第0個人出牌完畢
房間號:8 第0個人出牌完畢
房間號:6 第0個人出牌完畢
房間號:4 第0個人出牌完畢
房間號:3 第0個人出牌完畢
房間號:7 第0個人出牌完畢
房間號:2 第1個人出牌完畢
房間號:5 第0個人出牌完畢
房間號:1 第0個人出牌完畢
房間號:0 第0個人出牌完畢
房間號:8 第1個人出牌完畢
房間號:1 第1個人出牌完畢
房間號:6 第1個人出牌完畢
房間號:9 第1個人出牌完畢
房間號:3 第1個人出牌完畢
房間號:0 第1個人出牌完畢
房間號:7 第1個人出牌完畢
房間號:2 第2個人出牌完畢
房間號:4 第1個人出牌完畢
房間號:5 第1個人出牌完畢
房間號:5 第2個人出牌完畢
房間號:4 第2個人出牌完畢
房間號:0 第2個人出牌完畢
房間號:3 第2個人出牌完畢
房間號:9 第2個人出牌完畢
房間號:1 第2個人出牌完畢
房間號:0 第3個人出牌完畢
房間號:1 第3個人出牌完畢
房間號:1 第0個人出牌完畢
房間號:8 第2個人出牌完畢
房間號:2 第3個人出牌完畢
房間號:1 第1個人出牌完畢
房間號:7 第2個人出牌完畢
房間號:7 第3個人出牌完畢
房間號:0 第0個人出牌完畢
房間號:6 第2個人出牌完畢
房間號:5 第3個人出牌完畢
房間號:9 第3個人出牌完畢
房間號:1 第2個人出牌完畢
房間號:4 第3個人出牌完畢
房間號:1 第3個人出牌完畢
房間號:2 第0個人出牌完畢
房間號:7 第0個人出牌完畢
房間號:0 第1個人出牌完畢
房間號:4 第0個人出牌完畢
房間號:4 第1個人出牌完畢
房間號:9 第0個人出牌完畢
房間號:5 第0個人出牌完畢
房間號:9 第1個人出牌完畢
房間號:6 第3個人出牌完畢
房間號:8 第3個人出牌完畢
房間號:4 第2個人出牌完畢
房間號:3 第3個人出牌完畢
房間號:0 第2個人出牌完畢
房間號:2 第1個人出牌完畢
房間號:9 第2個人出牌完畢
房間號:7 第1個人出牌完畢
房間號:2 第2個人出牌完畢
房間號:7 第2個人出牌完畢
房間號:4 第3個人出牌完畢
房間號:9 第3個人出牌完畢
房間號:7 第3個人出牌完畢
房間號:0 第3個人出牌完畢
房間號:2 第3個人出牌完畢
房間號:9 第0個人出牌完畢
房間號:0 第0個人出牌完畢
房間號:9 第1個人出牌完畢
房間號:9 第2個人出牌完畢
 */

結論:可以看出,棋牌中房間之間完全是獨立的,每個房間打牌的消息只要保證順序一致就行了。 房間之間,完全可以併發處理。 你找出任何一個房間,他裏面打牌順序是一致的0-1-2-3-0...。 核心之處就在於 同步方法的使用,使得一個操作想進行時,鎖住當前所在這個房間,使得邏輯能夠正確的順序處理。

 

而不是像Node.js這樣,100個房間落在一個線程上,這樣真的就是1個房間邏輯在執行時,其它99個房間傻傻的等着。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章