用Java设计多线程矩阵 [英] Designing a multi-thread matrix in Java

查看:81
本文介绍了用Java设计多线程矩阵的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个矩阵,该矩阵实现了约翰·康威(John Conway)的生活模拟器,其中每个单元格代表生命或缺乏生命.

I have a matrix that implements John Conway's life simulator in which every cell represents either life or lack of it.

每个生命周期都遵循以下规则:

Every life cycle follows these rules:

  1. 具有少于两个活邻居的任何活细胞都会死亡,好像是由于人口不足造成的.

  1. Any live cell with fewer than two live neighbors dies, as if caused by under-population.

任何有两个或三个活邻居的活细胞都可以存活到下一代.

Any live cell with two or three live neighbors lives on to the next generation.

具有三个以上活邻居的任何活细胞都会死去,就像人满为患一样.

Any live cell with more than three live neighbors dies, as if by overcrowding.

任何具有三个活邻居的死细胞都变成一个活细胞,就像通过繁殖一样.

Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.

每个单元格都有一个线程,该线程将按照上面列出的规则执行更改.

Every cell will have a thread that will perform the changes by the rules listed above.

我实现了这些类:

import java.util.Random;

public class LifeMatrix {
    Cell[][] mat;
    public Action currentAction = Action.WAIT_FOR_COMMAND;
    public Action changeAction;

    public enum Action {
        CHECK_NEIGHBORS_STATE,
        CHANGE_LIFE_STATE,
        WAIT_FOR_COMMAND
    }

    // creates a life matrix with all cells alive or dead or random between dead or alive
    public LifeMatrix(int length, int width) {
        mat = new Cell[length][width];

        for (int i = 0; i < length; i++) { // populate the matrix with cells randomly alive or dead
            for (int j = 0; j < width; j++) {
                mat[i][j] = new Cell(this, i, j, (new Random()).nextBoolean());
                mat[i][j].start();
            }

        }
    }

    public boolean isValidMatrixAddress(int x, int y) {
        return x >= 0 && x < mat.length && y >= 0 && y < mat[x].length;
    }

    public int getAliveNeighborsOf(int x, int y) {
        return mat[x][y].getAliveNeighbors();
    }

    public String toString() {
        String res = "";
        for (int i = 0; i < mat.length; i++) { // populate the matrix with cells randomly alive or
                                               // dead
            for (int j = 0; j < mat[i].length; j++) {
                res += (mat[i][j].getAlive() ? "+" : "-") + "  ";
            }
            res += "\n";
        }
        return res;
    }


    public void changeAction(Action a) {
        // TODO Auto-generated method stub
        currentAction=a;
        notifyAll();                 //NOTIFY WHO??
    }
}


/**
 * Class Cell represents one cell in a life matrix
 */
public class Cell extends Thread {
    private LifeMatrix ownerLifeMat; // the matrix owner of the cell
    private boolean alive;
    private int xCoordinate, yCoordinate;

    public void run() {
        boolean newAlive;

        while (true) {
            while (! (ownerLifeMat.currentAction==Action.CHECK_NEIGHBORS_STATE)){
                synchronized (this) {//TODO to check if correct


                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println("Interrupted while waiting to check neighbors");
                }}
            }
            // now check neighbors
            newAlive = decideNewLifeState();

            // wait for all threads to finish checking their neighbors
            while (! (ownerLifeMat.currentAction == Action.CHANGE_LIFE_STATE)) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println("Interrupted while waiting to change life state");
                };
            }

            // all threads finished checking neighbors now change life state
            alive = newAlive;
        }
    }

    // checking the state of neighbors and
    // returns true if next life state will be alive
    // returns false if next life state will be dead
    private boolean decideNewLifeState() {
        if (alive == false && getAliveNeighbors() == 3)
            return true; // birth
        else if (alive
                && (getAliveNeighbors() == 0 || getAliveNeighbors() == 1)
                || getAliveNeighbors() >= 4)
            return false; // death
        else
            return alive; // same state remains

    }

    public Cell(LifeMatrix matLifeOwner, int xCoordinate, int yCoordinate, boolean alive) {
        this.ownerLifeMat = matLifeOwner;
        this.xCoordinate = xCoordinate;
        this.yCoordinate = yCoordinate;
        this.alive = alive;
    }

    // copy constructor
    public Cell(Cell c, LifeMatrix matOwner) {
        this.ownerLifeMat = matOwner;
        this.xCoordinate = c.xCoordinate;
        this.yCoordinate = c.yCoordinate;
        this.alive = c.alive;
    }

    public boolean getAlive() {
        return alive;
    }

    public void setAlive(boolean alive) {
        this.alive = alive;
    }

    public int getAliveNeighbors() { // returns number of alive neighbors the cell has
        int res = 0;
        if (ownerLifeMat.isValidMatrixAddress(xCoordinate - 1, yCoordinate - 1) && ownerLifeMat.mat[xCoordinate - 1][yCoordinate - 1].alive)
            res++;
        if (ownerLifeMat.isValidMatrixAddress(xCoordinate - 1, yCoordinate) && ownerLifeMat.mat[xCoordinate - 1][yCoordinate].alive)
            res++;
        if (ownerLifeMat.isValidMatrixAddress(xCoordinate - 1, yCoordinate + 1) && ownerLifeMat.mat[xCoordinate - 1][yCoordinate + 1].alive)
            res++;
        if (ownerLifeMat.isValidMatrixAddress(xCoordinate, yCoordinate - 1) && ownerLifeMat.mat[xCoordinate][yCoordinate - 1].alive)
            res++;
        if (ownerLifeMat.isValidMatrixAddress(xCoordinate, yCoordinate + 1) && ownerLifeMat.mat[xCoordinate][yCoordinate + 1].alive)
            res++;
        if (ownerLifeMat.isValidMatrixAddress(xCoordinate + 1, yCoordinate - 1) && ownerLifeMat.mat[xCoordinate + 1][yCoordinate - 1].alive)
            res++;
        if (ownerLifeMat.isValidMatrixAddress(xCoordinate + 1, yCoordinate) && ownerLifeMat.mat[xCoordinate + 1][yCoordinate].alive)
            res++;
        if (ownerLifeMat.isValidMatrixAddress(xCoordinate + 1, yCoordinate + 1) && ownerLifeMat.mat[xCoordinate + 1][yCoordinate + 1].alive)
            res++;
        return res;
    }

}


public class LifeGameLaunch {

    public static void main(String[] args) {
        LifeMatrix lifeMat;
        int width, length, populate, usersResponse;
        boolean userWantsNewGame = true;
        while (userWantsNewGame) {
            userWantsNewGame = false; // in order to finish the program if user presses
                                      // "No" and not "Cancel"
            width = Integer.parseInt(JOptionPane.showInputDialog(
                    "Welcome to John Conway's life simulator! \n"
                            + "Please enter WIDTH of the matrix:"));
            length = Integer.parseInt(JOptionPane.showInputDialog(
                    "Welcome to John Conway's life simulator! \n"
                            + "Please enter LENGTH of the matrix:"));


            lifeMat = new LifeMatrix(length, width);

            usersResponse = JOptionPane.showConfirmDialog(null, lifeMat + "\nNext cycle?");
            while (usersResponse == JOptionPane.YES_OPTION) {
                if (usersResponse == JOptionPane.YES_OPTION) {
                    lifeMat.changeAction(Action.CHECK_NEIGHBORS_STATE);
                } 
                else if (usersResponse == JOptionPane.NO_OPTION) {
                    return;
                }
                // TODO leave only yes and cancel options
                usersResponse = JOptionPane.showConfirmDialog(null, lifeMat + "\nNext cycle?");
            }
            if (usersResponse == JOptionPane.CANCEL_OPTION) {
                userWantsNewGame = true;
            }
        }
    }
}

我的麻烦是同步线程: 每个单元(线程)都必须在所有线程都检查了它们的邻居之后才更改其生命/死亡状态.用户将通过单击按钮来调用下一个生命周期.

My trouble is to synchronize the threads: Every cell(a thread) must change its life/death state only after all threads have checked their neighbors. The user will invoke every next life cycle by clicking a button.

我的逻辑是让每个单元(线程)运行并等待LifeMatrix类中的变量currentAction表示的正确操作状态,然后继续执行.执行所需的操作.

My logic, as can be understood from the run() method is to let every cell(thread) run and wait for the right action state that is represented by the variable currentAction in LifeMatrix class and go ahead and execute the needed action.

我遇到的困难是如何将这些消息传递给线程,以知道何时等待以及何时执行下一个动作?

What I struggle with is how do I pass these messages to the threads to know when to wait and when execute next action?

任何欢迎更改程序设计的建议,只要每个单元都使用单独的线程来实现!

推荐答案

使用(已更新为使用2个障碍,并利用内部类使单元格看起来更短,更干净)

(updated to use 2 Barriers, and make use of inner class to make cell looks shorter and cleaner)

伪代码:

public class LifeMatrix {
    private CyclicBarrier cycleBarrier;
    private CyclicBarrier cellUpdateBarrier;
    //.....

    public LifeMatrix(int length, int width) {
        cycleBarrier = new CyclicBarrier(length * width + 1);
        cellUpdateBarrier = new CyclicBarrier(length * width);

        // follow logic of old constructor
    }

    public void changeAction(Action a) {
        //....
        cycleBarrier.await()
    }

    // inner class for cell
    public class Cell implements Runnable {
        // ....

        @Override
        public void run() {
             while (...) {
                 cycleBarrier.await();  // wait until start of cycle
                 boolean isAlive = decideNewLifeState();
                 cellUpdateBarrier.await();  // wait until everyone completed
                 this.alive = isAlive;
             }
        }
    }
}

这篇关于用Java设计多线程矩阵的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆