0

我有这门课

package net.omnosis.mazegame.components;

import net.omnosis.mazegame.SlicedBitmap;
import android.graphics.Bitmap;

public class PlayerLayer extends DrawableLayer {

    private Player player;
    private XY tileImageSize;

    private int[] move = new int[] { 1, 2, 3, 4, 3, 2, 1, 6, 7, 8, 7, 6 };
    //private int[] move = new int[] { 8 };

    private int moveCount;
    private int moveCountMax = move.length;

    private Bitmap playerBitmap;
    public SlicedBitmap playerTiles;

    private int line;

    private static final int VERTICAL = 0;
    private static final int HORIZONTAL = 8;

    public PlayerLayer(Player player, Bitmap playerBitmap, XY tileImageSize) {

        this.playerBitmap = playerBitmap;
        this.tileImageSize = tileImageSize;
        playerTiles = new SlicedBitmap(playerBitmap, tileImageSize.x(), tileImageSize.y());

        setPlayer(player);

        update();
    }

    public final void setPlayer(Player player) {
        if (this.player != null) {
            this.player.removeListener(this);
        }

        this.player = player;
        player.addListener(this);
        update();
    }

    public void updateDirection() {
        Direction dir = player.getHeading();

        if (dir == Direction.LEFT || dir == Direction.RIGHT) {
            line = HORIZONTAL;
        } else if (dir == Direction.TOP || dir == Direction.BOTTOM) {
            line = VERTICAL;
        }
    }

    public synchronized void animate() {

        if (player.isMoving()) {

            moveCount++;

            if (moveCount >= moveCountMax) {

                player.finishMove();
                moveCount = 0;
            }
        } else {

        }

        updateDirection();
        super.update();
    }

    public void update() {
        updateDirection();
        super.update();
    }

    public XY getSpritePos() {
        XY playerPos = new XY(player.getCurrentPosition().x() * tileImageSize.x() + (tileImageSize.x() / 2), player.getCurrentPosition().y() * tileImageSize.y() + (tileImageSize.y() / 2));
        XY animationPos = getAnimationPos();
        return playerPos.add(animationPos);
    }

    public XY getAnimationPos() {
        double step = (double) tileImageSize.x() / moveCountMax * moveCount;
        return player.getHeading().multiply((int) step);
    }

    public Bitmap getBitmap() {

        if (moveCount >= moveCountMax) {
            System.out.println("BUG! MORE: " + moveCount + "  max: " + moveCountMax);
            moveCount = 0;
        }
        return playerTiles.getTile(move[moveCount] + line);
    }
}

一个线程animate每 10 毫秒调用一次该方法。有时我会得到这个输出:BUG! MORE: 12 max: 12这是因为我在方法中再次检查了值getBitmap()。为什么?

我不明白,如果动画是synchronized,moveCount 怎么可能超过 11?

如果模拟器滞后,这种情况会更频繁地发生。

4

2 回答 2

3

moveCount在一个synchronized块中递增和重置,但是当您访问方法moveCount中的变量时,您没有在同一个锁上同步getBitmap()

这意味着线程 A 可能位于animate()方法的中间,并且已递增moveCount到等于moveCountMax。然后线程 B 进入getBitmap()并读取线程 A 重置为 0moveCount 之前的值。moveCount

通常,您不仅需要在写入变量的值时进行同步,还需要在从变量中读取时进行同步(在同一个锁上),特别是如果对该变量的操作之一(如您的animate()方法)涉及复合操作(递增,然后可能重置为 0)

顺便说一句,如果moveCountMax是一个常数值 ( = moves.length),则将其标记为final

于 2012-09-13T20:10:44.720 回答
1

您需要同步对共享可变数据的所有访问。您在增量上同步,这很好,但您不会在读入时同步getBitmap。这意味着线程可以moveCountgetBitmap递增时或之后立即读取。

想象一下,您递增moveCount并且在递增线程将其设置为 0 之前,另一个线程调用 getBitmap 的情况,if (moveCount >= moveCountMax) {此时可能为真。

于 2012-09-13T20:12:21.383 回答