gpt4 book ai didi

java - 重复启动和停止多个线程

转载 作者:行者123 更新时间:2023-12-02 04:54:40 25 4
gpt4 key购买 nike

我有一个网格(一个矩阵)。每个细胞都是一个对象。一开始,有五个(随机)这些单元被选为“跳跃单元”,用户可以在其中跳跃以逃离敌人。每个单元格都有一个随机倒计时。如果倒计时变为 0,则该单元格将变为普通单元格,并且玩家无法再跳入其中。如果用户按下 Enter 键,玩家将跳转到当前的“跳跃单元”之一,同时随机选择一个新的跳跃单元。

有时,当我玩这个游戏并按 Enter 时,我会收到 ConcurrentModificationException,我不知道为什么。

可以按 Esc 键重置网格情况(创建新的 5 个跳跃单元格)。如果我反复按 Esc 按钮,经常会发生一些新的跳跃单元不会减少其倒计时。

这是代码:

细胞

public class Cell implements Runnable {

/** indicates whether this cell is the target cell */
private boolean isTarget;

/** indicates whether this cell is a jump cell */
private boolean isJumpCell;

/** associated number to this cell */
private int number;

/** living time of this cell */
private int countdown;

/** coordinates of this cell in the grid */
private int i;
private int j;

private boolean running;
private boolean alreadyStarted;

private Thread countdownT;

public Cell(int i, int j) {
this.i = i;
this.j = j;
countdown = (int)(Math.random() * 6) + 3;
countdownT = new Thread(this);
}

/**
* Starts the thread or restart if already started in the past
*/
public void start() {
if(alreadyStarted) {
restart();
} else {
countdownT.start();
running = true;
alreadyStarted = true;
isJumpCell = true;
}
}

/**
* This cell is restarted
*/
public void restart() {
isJumpCell = true;
running = true;
countdown = (int)(Math.random() * 6) + 3;
}

/**
* Stops the update of this cell (is not a jump cell anymore)
*/
public void stop() {
isJumpCell = false;
running = false;
}

@Override
public void run() {
while (running) {
try {
Thread.sleep(1000);
countdown--;
// if the countdown becomes 0, stop running
// not a jump cell anymore
if (countdown == 0) {
running = false;
isJumpCell = false;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

网格

我把必要的代码放了

public Grid(RedEnemy p) {
this.p = p;
grid = new Cell[ROWS][COLS];
for(int i = 0; i < ROWS; i++) {
for(int j = 0; j < COLS; j++) {
grid[i][j] = new Cell(i,j);
}
}
jumpCells = new ArrayList<Cell>();

// initial setup
numJumpCells = 5;

grid[target_y][target_x].setTarget(true);

for(int n = 0; n < numJumpCells; n++) {
int i = (int) (Math.random() * (ROWS - 1));
int j = (int) (Math.random() * (COLS - 1));
grid[i][j].setTarget(false);
grid[i][j].setNumber(n + 1);
jumpCells.add(grid[i][j]);
jumpCells.get(n).start();
}
}

public void reset() {
for(Cell cell : jumpCells) {
cell.stop();
}
jumpCells.clear();
target_x = 0;
target_y = 0;
numJumpCells = 5;
for(int n = 0; n < numJumpCells; n++) {
int i = (int) (Math.random() * (ROWS - 1));
int j = (int) (Math.random() * (COLS - 1));
grid[i][j].setTarget(false);
grid[i][j].setNumber(n + 1);
jumpCells.add(grid[i][j]);
jumpCells.get(n).start();
}
}

/**
* Performs the jump
*/
public void jump() {
// always jumps in the first jump cell among the current ones
Cell jumpCell = jumpCells.get(0);
// updates the position of the player
target_y = jumpCell.getI();
target_x = jumpCell.getJ();
// updates the cell in the grid
grid[jumpCell.getI()][jumpCell.getJ()].setJumpCell(false);
grid[jumpCell.getI()][jumpCell.getJ()].setTarget(true);
// stop the cell in which the player is jumped
jumpCells.get(0).stop();
// removes the cell from the list of the jump cells
jumpCells.remove(0);

// updates the position of the player in the enemy class
p.setTargetY(target_y * SIZE);
p.setTargetX(target_x * SIZE);

// create a new jump cell at random
int i = (int) (Math.random() * (ROWS - 1));
int j = (int) (Math.random() * (COLS - 1));
//grid[i][j].setJumpCell(true);
grid[i][j].setTarget(false);
grid[i][j].setNumber(jumpCells.size() - 1);
jumpCells.add(grid[i][j]);
jumpCells.get(jumpCells.size() - 1).start();
}

// UPDATE
public void update(float delta) {
for(Iterator<Cell> it = jumpCells.iterator(); it.hasNext();) {
Cell c = it.next();
if(!c.isJumpCell()) {
it.remove();
numJumpCells--;
}
}
}

// DRAW
public void draw(Graphics dbg) {
// draw the grid
dbg.setColor(Color.BLACK);
int heightOfRow = GamePanel.PHEIGHT / ROWS;
for (int i = 0; i < ROWS; i++)
dbg.drawLine(0, i * heightOfRow, GamePanel.PWIDTH, i * heightOfRow);

int widthdOfRow = GamePanel.PWIDTH / COLS;
for (int i = 0; i < COLS; i++)
dbg.drawLine(i * widthdOfRow, 0, i * widthdOfRow, GamePanel.PHEIGHT);

// draw jump cells
dbg.setColor(Color.RED);
dbg.setFont(new Font("TimesRoman", Font.PLAIN, 25));
for(Iterator<Cell> it = jumpCells.iterator(); it.hasNext();) {
Cell c = it.next();
dbg.drawRect(c.getJ() * SIZE, c.getI() * SIZE, SIZE, SIZE);
dbg.setColor(Color.BLUE);
dbg.drawString(String.valueOf(c.getCountdown()), c.getJ() * SIZE + SIZE/2, c.getI() * SIZE + SIZE/2);
dbg.setColor(Color.RED);
}

// draw target
dbg.setColor(Color.BLUE);
dbg.fillRect(target_x * SIZE, target_y * SIZE, SIZE, SIZE);
}

编辑

定时器线程

public class TimerThread implements Runnable {

private Grid grid;

private boolean isRunning;

public TimerThread(Grid grid) {
this.grid = grid;
}

public void start() {
isRunning = true;
}

public void stop() {
isRunning = false;
}

@Override
public void run() {
while(isRunning) {
// retrieves the list of the jump cells
ArrayList<Cell> jumpCells = (ArrayList<Cell>) grid.getJumpCells();

// wait one second
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

// updates the jump cells
for(Cell c : jumpCells) {
if(c.getCountdown() > 0) {
c.decreaseCountdown();
} else {
c.setJumpCell(false);
}
}
}
}

或者...

@Override
public void run() {
while(isRunning) {
// retrieves all the cells
Cell[][] cells = grid.getGrid();

// wait one second
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

// updates the cells
for(int i = 0; i < cells.length; i++) {
for(int j = 0; j < cells[0].length; j++) {
if(cells[i][j].isJumpCell()) {
if(cells[i][j].getCountdown() > 0) {
cells[i][j].decreaseCountdown();
} else {
cells[i][j].setJumpCell(false);
}
}
}
}
}
}

好的,最后一次更新似乎工作正常! :)

最佳答案

这只是一个猜测,因为您没有堆栈跟踪供我们跟踪,但我怀疑当您收到 ConcurrentModificationException 时发生的情况是您正在执行更新(迭代jumpCells),同时您尝试计算跳跃的效果(并删除其中一个 jumpCells)。这是不允许的。

您可以使用并发集合来允许类似的操作,但这只会强制阻塞,并且对于您想要执行的操作来说并不是很干净。

您应该只在更新期间更改跳跃单元。您可以通过让跳转方法设置一些在更新期间检查的变量来做到这一点。

最好的办法是不要对单元计时器进行多线程处理。没有理由在此应用程序中使用如此多的线程。

相反,使用单个计时器线程每秒(甚至每 100 毫秒)迭代所有单元格并更新它们。向单元格添加同步锁,以确保它们不会同时被游戏循环和计时器修改。

完整的堆栈跟踪将有助于诊断您遇到的确切问题。而且,如果您必须多线程,请学习如何很好地使用调试器。

关于java - 重复启动和停止多个线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28908880/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com