我正在做一个小的GUI应用程序来模拟游泳比赛。我有一个单独的游泳池和记分牌的图形用户界面,游泳者被5个线程移动,当他们到达触摸板时,我编码在记分板上显示该时间。
问题是每当在记分板中显示标签的那些时间被更新时,游泳者突然移回到起始位置(不是刚刚消失并出现在起点处的连续运动)而不停留在触摸板附近。但如果标签没有更新,这是有效的。
这不是完整的代码,但这是代码段,负责游泳者的移动以及游泳者完成长度时更新时间标签。
private final Map<Swimmer, JLabel> mapLaneTime = new HashMap<>();
private void startTheGame(final String swimmingStyle) {
final ArrayList<Swimmer> listSwimmer =
new ArrayList<> (mapSwimmers.keySet());
for (int i = 0; i < mapSwimmers.size(); i++) {
final Swimmer swmr = listSwimmer.get(i);
// set up the intial position of the JLabel to the swimmer
swmr.setCurrentPosition(mapSwimmers.get(swmr).getX());
new Thread(new Runnable() {
@Override
public void run() {
try {
swmr.slowDown();
JLabel lblSwmr = mapSwimmers.get(swmr);
swmr.doSwimmingStyle(swimmingStyle);
int startPosition = swmr.getCurrentPosition();
while ((swmr.getCurrentPosition()
!= swmr.getSwimLane().getLength()
+ startPosition)) {
lblSwmr.setLocation(swmr.doLegMovements(),
lblSwmr.getY());
swmr.doHandMovements();
swmr.speedUp();
}
// time takes for the swimmer to touch the touch pad
double time = swmr.touchTheTouchPad(swimmingEvent);
/** problem comes when the below line is present it is the way to set text
** to the label if this is not here swimmers properly end the length
** without appearing at the starting position when ever they finish the
** length
**/
mapLaneTime.get(swmr).setText(time + "");
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
swmr.giveUp();
}
}
}).start();
}
}
线程完全没有问题。不要在乎其他方法。其他实现没有任何问题。
对不起,我忘了提及swmr.giveUP()是释放锁的方法(Lock lock = new ReentrantLock())。锁定在Swimmer类中定义。游泳者课程中还有另一个线程来更新使用相同锁定的游泳者的位置
这是Swimmer类的完整代码,ScoreBoard类
Swimmer class(这是一个抽象类,有两个子类MaleSwimmer和FemaleSwimmer)
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public abstract class Swimmer extends Person {
private final String gender; // gender of the Swimmer
private final String costumeColor; //color of the costume
private final int personalBest;
private volatile int currentPosition;
private SwimLane swimLane;
private final Lock lock; // lock for the thread
private final Condition condition;
protected Swimmer(String name, String gender, String costumeColor) {
super(name);
this.gender = gender;
this.costumeColor = costumeColor;
Random random = new Random();
this.personalBest = random.nextInt(20) + 8;
lock = new ReentrantLock();
condition = lock.newCondition();
}
public SwimLane getSwimLane() {
return this.swimLane;
}
/**
* @return the color of the swimming costume
*/
protected String getDressColor() {
return this.costumeColor;
}
/**
* perform hand movements
*/
protected void doHandMovements() {
this.condition.signalAll();
}
/**
* perform leg movements
*
* @return
*/
protected int doLegMovements() {
return this.currentPosition;
}
/**
* perform Butterfly stroke
*
* @param sleepTime
*/
protected abstract void doButterflyStroke(int sleepTime);
/**
* perform Backstroke
*
* @param sleepTime
*/
protected abstract void doBackStroke(int sleepTime);
/**
* perform Breaststroke
*
* @param sleepTime
*/
protected abstract void doBreastStroke(int sleepTime);
/**
* perform Freestyle
*
* @param sleepTime
*/
protected abstract void doFreeStyle(int sleepTime);
public void doSwimmingStyle(String style) {
switch (style) {
case "Freestyle":
doFreeStyle(personalBest);
break;
case "Backstroke":
doBackStroke(personalBest);
break;
case "Butterfly Stroke":
doButterflyStroke(personalBest);
break;
case "Breaststroke":
doBreastStroke(personalBest);
break;
}
this.swimLane.getTouchPad().startTimer(); // start the timer when swimmer starts to swim
}
void updatePosition(int sleepTime, double factor) {
final int swimTime = (int) (sleepTime * factor);
new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock(); // lock the thread
int endPosition = currentPosition + swimLane.getLength(); // length of the lane from staring to end
while (currentPosition <= endPosition) {
currentPosition++;
Thread.sleep(swimTime);
condition.signal();
condition.await();
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
lock.unlock(); // give up the lock from the thread
}
}
}).start();
}
public int getPersonalBest() {
return this.personalBest;
}
public void setCurrentPosition(int currentPosition) {
this.currentPosition = currentPosition;
}
public int getCurrentPosition() {
return this.currentPosition;
}
public void setSwimLane(SwimLane swimLane) {
this.swimLane = swimLane;
}
/**
* When swimmer finish the event swimmer should touch the touch pad. This
* method achieve that task
*
* @param swimmingEvent
* @return swimmer's finishing time
*/
public double touchTheTouchPad(SwimmingEvent swimmingEvent) {
return this.swimLane.getTouchPad().notifyScoreBoard(this,
swimmingEvent);
}
public void slowDown() throws InterruptedException {
this.lock.lock();
}
public void speedUp() throws InterruptedException {
this.condition.awaitNanos(500);
}
public void giveUp() {
this.lock.unlock();
}
}
class ScoreBoard
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ScoreBoard implements Serializable {
Queue<Double> time;
Queue<Swimmer> swimmers;
Map<Swimmer, Double> finalResults;
private int numberOfRows;
private final Lock lock;
private final Condition condition;
public ScoreBoard() {
time = new LinkedList<>();
swimmers = new LinkedList<>();
finalResults = new LinkedHashMap<>();
lock = new ReentrantLock();
condition = lock.newCondition();
}
/**
* This method will add swimmer and timeTaken to the list
*
* @param swimmer swimmer who completed the event
* @param timeTaken time took for swimmer to complete the event
*/
public void updateList(Swimmer swimmer, double timeTaken) {
time.add(timeTaken);
swimmers.add(swimmer);
}
/**
* This method will start the process of the Score Board
*/
public void powerUp() {
new Thread(new Runnable() {
@Override
public void run() {
try {
// swimmer will take more than 4s to complete a game
Thread.sleep(4000);
lock.lock();
while (swimmers.size() != numberOfRows) {
// wait this thread untill this is awoken
Thread.sleep(100);
}
comapreTimes();
condition.signal();
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
lock.unlock();
}
}
}).start();
}
/**
* This method will set the number of rows in Score Board
*
* @param numberOfRows number of rows that should be in Score Board
*/
public void setNumberOfRows(int numberOfRows) {
this.numberOfRows = numberOfRows;
}
/**
* This method will pass the lock to the thread inside the powerUp method
*/
public void lockTheScoreBoard() {
this.lock.lock();
}
public void unlockTheScoreBoard() {
this.lock.unlock();
}
public void awaitScoreBoard() throws InterruptedException {
this.condition.await();
}
void comapreTimes() {
for (Swimmer s : swimmers) {
this.finalResults.put(s, time.poll());
// need to do something more in here
}
}
public Map<Swimmer, Double> getFinalResults() {
new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
condition.await();
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
lock.unlock();
}
}
}).start();
return this.finalResults;
}
}
我也尝试使用SwingWorker线程更新JLabel,但是出现了同样的问题。
答案 0 :(得分:0)
首先,swmr.giveUp();应该从最后移动到为InterruptedExcveption执行的部分。
为什么每个煨者都放弃了?只有宽松者应该。
检查是否会解决问题。也许情况就是这样。
你知道,我认为设置JLabel的文本没有问题,它只是强制重绘窗口,所以这就是为什么你看到所有的游泳者都在startnig,swmr.giveUp();重新开始他们的职位?
如果是这种情况,那就是为什么你在设置JLabel文本后在beginnig上看到所有这些,因为他们已经有了这个位置,但是如果你不重绘,你将看不到他们的新位置。< / p>