[英]java thread safety error in synchronized method
我有這堂課
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);
}
}
線程每10毫秒調用一次animate
方法。 有時我得到以下輸出: BUG! MORE: 12 max: 12
BUG! MORE: 12 max: 12
這是因為我在getBitmap()
方法中再次檢查了值。 為什么?
我不明白,如果動畫是synchronized
,moveCount怎么會大於11?
如果模擬器滯后,則這種情況會更頻繁地發生。
您將在已synchronized
塊中遞增和重置moveCount
,但是當您在getBitmap()
方法中訪問moveCount
變量時,您並未在同一鎖上進行同步。
這意味着線程A可以在animate()
方法的中間,並且將moveCount
遞增為與moveCountMax
相等。 然后,線程B進入getBitmap()
並讀取moveCount
的值, 然后線程A將moveCount
重置為0。
通常,不僅需要在寫入變量的值時同步,還需要在讀取變量時(在同一鎖上)進行同步,尤其是在對該變量進行的一項操作(例如animate()
方法)時,尤其要進行同步。涉及復合操作(遞增,然后可能重置為0)
順便說一句,如果moveCountMax
是一個常量值( = moves.length
),則將其標記為final
。
您需要同步對共享可變數據的所有訪問。 您可以在增量上進行同步,這很好,但是您不能在getBitmap
的讀取上進行同步。 這意味着線程可以在遞增或緊隨其后讀取getBitmap
moveCount
。
假設您增加了moveCount
並且在該遞增線程將其設置為0之前,另一個線程調用了getBitmap,其中if (moveCount >= moveCountMax) {
可以為true。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.