首页 > 编程语言 > 详细

COMP0008 Written Java Coursework

时间:2020-01-20 21:15:32      阅读:53      评论:0      收藏:0      [点我收藏+]


COMP0008 Written Java Coursework (2019/20)
NOTE: Your final Moodle submission will consist of a number of parts:
1. Three different versions of the “ConwaysGameOfLife.java” file after different
modifications called: “ConwaysGameOfLife_VERSION1.java”,
“ConwaysGameOfLife_VERSION2.java”,
“ConwaysGameOfLife_VERSION3.java”.
(Thus you should only modify this file and not create other Java files.)
2. A PDF file giving answers to the questions below (given with bold stars). You
can write this description using Word or Latex - as long as you submit a PDF
version in the end.
Getting going ...
Take your favourite Java IDE and install:
Conway’s Game of Life
From the github:
https://github.com/Burke9077/Conway-s-Game-of-Life.git
(You should be familiar with how to do this.)
This is quite a popular version of the game mentioned in a number of websites … but we
are going to analyse its faults and try to improve its structure … in particular focusing on
concurrency.
Build the system, run it and play around with the GUI to get a feel for how it works.
You should take copies of your Java files after each of these tasks to be submitted to
Moodle. [Also this will enable you to roll back to a previous working version if revisions all
go horribly wrong! Although ideally you would be using a revision control system like git.]
Task 1: To get you familiar with the code.
Choose the File > Options menu to set the rate of the game at 20 frames per second.
Choose the Game > Autofill menu item and select 40% random tiles to fill.
Now start the game running … and wait.
Eventually (after a number of minutes) … it will crash with:
---
Exception in thread "Thread-0" java.lang.StackOverflowError
at java.desktop/java.awt.event.InvocationEvent.<init>(InvocationEvent.java:286)
at java.desktop/java.awt.event.InvocationEvent.<init>(InvocationEvent.java:172)
at
java.desktop/javax.swing.RepaintManager.scheduleProcessingRunnable(RepaintManager.
java:1485)
at
java.desktop/javax.swing.RepaintManager.addDirtyRegion0(RepaintManager.java:474)
at
java.desktop/javax.swing.RepaintManager.addDirtyRegion(RepaintManager.java:496)
at java.desktop/javax.swing.JComponent.repaint(JComponent.java:4836)
at java.desktop/java.awt.Component.repaint(Component.java:3352)
at ConwaysGameOfLife$GameBoard.run(ConwaysGameOfLife.java:311)
at ConwaysGameOfLife$GameBoard.run(ConwaysGameOfLife.java:314)
… and then it repeats this same line hundreds of times !!!
Now you might be tempted to post out a question to “StackOverflow” to resolve this
StackOverflowException! But avoid doing this since I think you can fix it yourself with only
3 line of code being changed!
Task 1 is to fix this bug and get familiar with how the code is working. You may not have
done any Java Swing programming before … so I’m going to describe how the system
COMP0008作业代做、代写java程序语言作业
generally works below but you may need to look up some further information describing
how Swing works.
But before reading below, have a look through the code and try to work out how it is
working (it is all in a single file “ConwaysGameOfLife.java”).
The system uses the Java Swing toolkit for the graphical elements. The “main” method
essentially sets up a “JFrame game = new ConwaysGameOfLife();” which is the main
public class in this file. A JFrame is the main graphical interface for the game. The main
method then sets up some settings before doing a “game.setVisible(true)” to make the GUI
visible.
The constructor of this class sets up all the graphical Swing components of the GUI
interface such as menu items, with “action listeners” referencing the class itself. The
“actionPerformed” method gets called when a menu item is selected. This looks up the
source of different events (such as “ae.getSource().equals(mi_game_play)” and then calls
the appropriate method “setGameBeingPlayed(true);”
This method then does:
public void setGameBeingPlayed(boolean isBeingPlayed) {
if (isBeingPlayed) {
mi_game_play.setEnabled(false);
mi_game_stop.setEnabled(true);
game = new Thread(gb_gameBoard);
game.start();
} else {
mi_game_play.setEnabled(true);
mi_game_stop.setEnabled(false);
game.interrupt();
} }
The first lines enable and disable particular menu items (mi_game_start and
mi_game_stop menu items). But the key lines are the creation of a new “game” thread and
starting this. And also calling an interrupt on it to stop this game thread.
The thread is created from the gb_gameBoard which you will see is created at the end of
the constructor and then added into the JFrame. This is actually the graphical game board
itself which is added onto the JFrame and it gets repainted using its paint() method to draw
the current position of “live squares” on the board.
The GameBoard is a private class and it probably has too many responsibilities:
private class GameBoard extends JPanel implements ComponentListener,
MouseListener, MouseMotionListener, Runnable {
It extends JPanel which means it is a Swing graphical panel (i.e. draws the board). It also
implements different listeners which means it can respond to mouse events and it also
implements a Runnable which is the game thread itself. So the GUI event thread may be
running through this class, for instance clicking a mouse will cause the “mouseReleased()”
method to be called by the GUI event thread. Changing the interface may cause the GUI
thread to call the paintComponent() or componentResized() methods. In addition there is
the run() method which clearly implements another user threads in this class. Look through
this run() method to see what it is doing.
Now what could be causing the StackOverflowError above?
Identify the issue and restructure the code so that it no longer throws this error. This will
only require a few lines of code to be changed. Ensure the interrupt mechanism to stop the
game still works as well though.
After fixing this bug … you should be able to run the game for a long time without having a
StackOverflowError resulting.
*** QUESTION 1: Describe what caused this bug and how you fixed it.
*** Take a copy of your Java code and label it
“ConwaysGameOfLife_VERSION1.java”
Task 2: Getting into trouble with concurrency.
It should be clear now that there are two threads running through the GameBoard class. A
GUI thread which is painting the squares (and also changing them on mouse events)
together with changing other aspects of the boards (for instance when resizing the board).
Also there is a user thread that is calculating how squares change for the next step in the
game. It seems the GameBoard class is responsible for too much and it’s sure to end in
disaster!
The GUI thread repaints the board by calling:
public void paintComponent(Graphics g) {
within the GameBoard class.
You may notice the lines:
try {
for (Point newPoint : point) {
// Draw new point
g.setColor(Color.blue);
g.fillRect(BLOCK_SIZE + (BLOCK_SIZE*newPoint.x), BLOCK_SIZE +
(BLOCK_SIZE*newPoint.y), BLOCK_SIZE, BLOCK_SIZE);
}
} catch (ConcurrentModificationException cme) {}
The catching (and then ignoring) of the “ConcurrentModificationException” sort of indicates
that we have a concurrency issue here! Add a “System.out.println(“CONCURRENCY
ISSUE !!!”)” into the code to see if we ever get this exception actually being thrown:
} catch (ConcurrentModificationException cme) {System.out.println("CONCURRENCY
EXCEPTION !!!");}
Running at 20 frames per second with 40% random squares … try changing the board by
clicking on it … or resizing the board … minimizing it and maximizing it (causing the
repaint method to be called). What you are trying to do is cause the “CONCURRENCY
EXCEPTION !!!” message to be displayed. It isn’t easy since it requires the GUI thread
and the game thread to collide in terms of accessing or modifying the game squares. But I
can produce multiple concurrency exceptions when drawing squares over the board with
the mouse button pressed while the game is running:
---
/usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java -javaagent:/home/ucackxb/software/idea?IC-183.4588.61/lib/idea_rt.jar=39515:/home/ucackxb/software/idea-IC-183.4588.61/bin -
Dfile.encoding=UTF-8 -classpath /home/ucackxb/COURSES/COMP0008/Conway-s?Game-of-Life_version2/out/production/Conway-s-Game-of-Life ConwaysGameOfLife
CONCURRENCY EXCEPTION !!!
CONCURRENCY EXCEPTION !!!
CONCURRENCY EXCEPTION !!!
CONCURRENCY EXCEPTION !!!
---
But you can actually get worse than this. By very quickly decreasing the size of the board
while it is being recalculated … you can get the user thread crashing out with an
ArrayIndexOutofBoundsException:
---
/usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java -javaagent:/home/ucackxb/software/idea?IC-183.4588.61/lib/idea_rt.jar=46389:/home/ucackxb/software/idea-IC-183.4588.61/bin -
Dfile.encoding=UTF-8 -classpath /home/ucackxb/COURSES/COMP0008/Conway-s?Game-of-Life_version2/out/production/Conway-s-Game-of-Life ConwaysGameOfLife
CONCURRENCY EXCEPTION !!!
CONCURRENCY EXCEPTION !!!
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 47
at ConwaysGameOfLife$GameBoard.run(ConwaysGameOfLife.java:285)
at java.base/java.lang.Thread.run(Thread.java:844)
---
(Make the board the size of the complete screen and start running it with 40% random
squares at 20 frames per second. Then press the icon to size it back to its default window
size … this almost guarantees it will throw this exception!)
Adjusting the graphics while it is running can also cause the GUI “AWT” thread to crash
out with a NullPointer exception which is most likely due to concurrency issues as well
(and then the GUI has crashed even though the rest of the program carries on running):
---
/usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java -javaagent:/home/ucackxb/software/idea?IC-183.4588.61/lib/idea_rt.jar=32797:/home/ucackxb/software/idea-IC-183.4588.61/bin -
Dfile.encoding=UTF-8 -classpath /home/ucackxb/COURSES/COMP0008/Conway-s?Game-of-Life_version2/out/production/Conway-s-Game-of-Life ConwaysGameOfLife
CONCURRENCY EXCEPTION !!!
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at
ConwaysGameOfLife$GameBoard.paintComponent(ConwaysGameOfLife.java:229)
at java.desktop/javax.swing.Jcomponent.paint(JComponent.java:1074)
---
For something that looks like it “roughly works” … it’s amazing how fragile it really is due to
not considering concurrency issues properly! (In fact putting in code that ignores
concurrency issues!)
Your second task it to fix these concurrency issues! Actually it may seem daunting but it
really comes down to identifying the shared state that is being modified by both threads
and ensuring that it is being operated on safely.
It may be useful to understand how ConcurrentModificationExceptions arise. The Brian
Goetz book explains this in Section 5.1.2 on page 82 (although it would be worthwhile
reading from the start of Chapter 5 on page 79 to Section 5.3 Blocking Queues and the
producer-consumer pattern on page 87 to get context for this and also to understand the
CopyOnWriteArrayList in Section 5.2.3 which we will be using).
It may also be useful to read Chapter 9 GUI Applications (pages 189-202) of the Brian
Goetz book to get familiar with both Swing GUIs and how threads work in the GUI
subsystem.
Change the ArrayList used currently for the “state” of the GameBoard to using the
concurrent CopyOnWriteArrayList object. Can you now make the system crash by adding
points and resizing the window?
*** QUESTION 2: Explain what is the key difference in how the
CopyOnWriteArrayList behaves compared to a normal ArrayList which has probably
made all these concurrency issues disappear (be specific about how a particular
mechanism used in the code works differently with these two classes).
*** QUESTION 3: What could be a disadvantage of using CopyOnWriteArrayList here
instead of a normal Arraylist? (Assuming we weren’t worried about the concurrency
issues!)
*** Take a copy of your Java code and label it
“ConwaysGameOfLife_VERSION2.java”
Task 3: Speed it up challenge!
This part is more challenging and the instructions are less detailed. So you will have to
work out how certain aspects need to be structured yourself and also worry about whether
your code is thread safe.
We first want to calculate the time it takes to do 100,000 cycles of the board without any
sleeping involved.
1. Comment out the sleep statement in the run() method so it runs at maximum speed.
2. Change the structure within the run() method so that it does 100,000 cycles of the board
and then finishes automatically.
3. Add “Date” objects (or similar) so that you can print out the time it takes to do the
100,000 cycles in milliseconds.
*** QUESTION 4: Do five runs and write down the different times your system takes
to do 100,000 cycles of the game of life (these will not all be shown on the screen
due to not having any sleep time in the code).
Now you probably have a multicore processor and the current system is only making use
of a single core since it is running a single thread for all the calculations.
We are going to restructure the code so that a number of threads each do the calculation
of one column of the shared board object. We will used the
Executors.newFixedThreadPool(4) to carry out the tasks (where we change the number of
threads in the pool to see how it affects the overall speed).
Create a FixedThreadPool executor at the top of the GameBoard class with initially 4
threads in the pool.
The restructuring will involve the current run() method creating a new Runnable object,
which you should call “BladeRunner”, for each “i” that it iterates over. Each “BladeRunner”
object will then do the calculation for that column of the boolean[][] gameBoard –
essentially doing the code within the central “i” loop of the current run() method. Each of
these “BladeRunner” objects will be queued on the thread pool so that it executes them.
But how to know when the current run() thread (within the GameBoard) can continue the
calculations for the next cycle of the board? Well … it should create a CountDownLatch
with the number set to the number of columns to calculate (i.e. the number of BladeRunner
objects created). This overall thread will then await on this latch before continuing the next
cycle. Each “BladeRunner” will then do a single countDown() on this latch at the end of its
run method to indicate it has finished. Thus the thread in the GameBoard will only continue
once all the columns have been calculated for the current board.
Your challenge is to work out the detail required to get this architecture to work and also to
worry about concurrency aspects – where might you need to add volatiles or
synchronization? You should be accurate in your analysis and not just add volatiles and
synchronization everywhere!
*** Take a copy of your Java code with 4 threads assigned to the thread pool. Label
the code: “ConwaysGameOfLife_VERSION3.java”
*** QUESTION 5: Experiment with different numbers of threads used in the thread
pool (for example try 1 thread, 2 threads, 4 threads, 6 threads, 8 threads, etc). Each
time record three (or better five) measurements of milliseconds for 100,000 cycles of
the board. Work out average / standard deviation of times and produce a table /
graph to show what might be the optimal number of threads for your system.
*** Please use the Moodle Forum to ask any questions about this coursework ***
*** Upload the three versions of your code and also your answers to Moodle ***

因为专业,所以值得信赖。如有需要,请加QQ99515681  微信:codehelp

COMP0008 Written Java Coursework

原文:https://www.cnblogs.com/jafga/p/12219314.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!