Counting the number of games played in 1 second using Java Threads
I want to know how many games my computer can play in 1000 ms. I did the tests before without using Threads (it plays 13k). Now that I think I'm using threads, I still get the same. Since I don't have much experience with Java threads, I assume I'm doing something wrong but I just can't get it.
Thanks in advance
public class SpeedTest<T extends BoardGame> implements Runnable
{
public static int gamesPlayed = 0;
private ElapsedTimer timer;
private double maxTime;
private BoardAgent<T> agent;
private BoardGame<T> game;
public SpeedTest(BoardGame<T> game, ElapsedTimer timer, double maxTime, Random rng)
{
this.game = game;
this.timer = timer;
this.maxTime = maxTime;
this.agent = new RandomAgent<T>(rng);
}
@Override
public void run()
{
while (true)
{
BoardGame<T> newBoard = game.copy();
while (!newBoard.isGameOver())
newBoard.makeMove(agent.move(newBoard));
gamesPlayed++;
if (timer.elapsedMilliseconds() > maxTime) {
break;
}
}
}
public static void main(String[] args)
{
Random rng = new Random();
BoardGame<Connect4> game = new Connect4(6, 7);
double maxTime = 1000;
ElapsedTimer timer = new ElapsedTimer();
SpeedTest<Connect4> speedTest1 = new SpeedTest<Connect4>(game, timer, maxTime, rng);
SpeedTest<Connect4> speedTest2 = new SpeedTest<Connect4>(game, timer, maxTime, rng);
Thread t1 = new Thread(speedTest1);
Thread t2 = new Thread开发者_高级运维(speedTest2);
t1.start();
t2.start();
try {
Thread.sleep((long) maxTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Games: " + SpeedTest.gamesPlayed);
}
}
I suspect that the reason that you are not seeing any speedup is that your application is only using 1 physical processor. If it is only using one processor, then the two threads won't be running in parallel. Instead, the processor will be "time-slicing" between the two threads.
What can you do about this?
Run on a dual-core etc processor. Or if you have a single processor machine with HT support, enable HT.
Run the test over a longer time; e.g. a number of minutes.
The reason I suggest the latter is that this could be a JVM warmup effect. When a JVM starts a new application, it needs to do a lot of class loading and JIT compilation behind the scenes. These tasks will be largely (if not totally) single-threaded. Running the tests over a longer period of time reduces the contribution of the "warm up" overheads to the average time per "game".
There is a fix that you ought to make to make the program thread-safe. Change
public static int gamesPlayed = 0;
to
private static final AtomicInteger gamesPlayed = new AtomicInteger();
and then use getAndIncrement()
to increment the counter and intValue()
to fetch its value. (This is simpler than having each thread maintain its own counter and summing them at the end.)
However, I strongly suspect that this change (or @Erik's alternative) will make little difference to the results you are seeing. I'm now sure it is either:
- JVM warmup issue as described above,
- a consequence of high object creation rates and/or heap starvation, or
- some hidden synchronization issue between the instances of your game.
Don't use a static int, use a normal member int.
Instead of the sleep, call .join
on both threads.
Then finally add the member ints.
精彩评论