联系方式

  • QQ:99515681
  • 邮箱:99515681@qq.com
  • 工作时间:8:00-23:00
  • 微信:codinghelp

您当前位置:首页 >> javajava

日期:2019-12-23 08:53

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.

注:您的最终 Moodle 提交将包括多个部分:

1. 三个不同版本的"ConwaysGameLife.java"文件经过不同的修改后调用:

"ConwaysGameOfLife_VERSION1.java"、"ConwaysGameOfLife_VERSION2.java"、"ConwaysGameOfLife_VERSION3.java"。

(因此,您只应修改此文件,而不应创建其他 Java 文件。

2. PDF 文件,提供以下问题的答案(以粗体星显示)。您可以使用 Word 或 Latex 编写此说明 - 只要您最终提交 PDF 版本即可。



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.]

开始...


采取您最喜爱的Java IDE并安装:康威的生活游戏

从 github:


https://github.com/Burke9077/Conway-s-Game-of-Life.git


这是一个相当流行的版本,在一些网站提到...但是我们要分析它的缺点,并试图改善它的结构...尤其注重并发性。

构建系统,运行它,并玩弄 GUI,以感受它是如何工作的。在将每个任务提交到后,应获取 Java 文件的副本。

穆德*此外,这将使您能够回滚到以前的工作版本,如果所有修订

去可怕的错误!虽然理想情况下,您将使用像 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:


选择"文件与选项"菜单,将游戏速率设置为每秒 20 帧。选择游戏 + 自动填充菜单项,并选择 40% 随机切片进行填充。

现在开始游戏运行...并等待。

最终(几分钟后)...它将崩溃与:

---

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!

现在,您可能很想向"堆栈溢出"发布一个问题,以解决此堆栈溢出异常问题!但避免这样做,因为我认为你可以修复它自己只有3行代码被改变!

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 generally works below but you may need to look up some further information describing how Swing works.

任务 1 是修复此 Bug 并熟悉代码的工作方式。您可能之前没有执行过任何 Java Swing 编程...因此,我将描述系统通常如何工作如下,但您可能需要查找一些进一步的信息,描述 Swing 的工作原理。

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”).

但在阅读下文之前,请浏览一下代码,并尝试找出它是如何工作的(这一切都在一个文件"ConwaysGameLife.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.

系统使用 Java 摆动工具包作为图形元素。"主"方法实质上设置了"JFrame 游戏 + 新的 ConwaysGameLife();",它是此文件中的主要公共类。JFrame 是游戏的主要图形界面。然后,主方法在进行"游戏.setVisible(true)"之前设置一些设置,以使 GUI 可见。

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);”


此类的构造函数设置 GUI 接口的所有图形 Swing 组件(如菜单项),"操作侦听器"引用类本身。选择菜单项时,将调用"操作执行"方法。这将查找不同事件的来源(如"ae.getSource(.equal(mi_game_play)",然后调用适当的方法"setGameTheSthe(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.

第一行启用和禁用特定的菜单项(mi_game_start和mi_game_stop菜单项)。但关键是创建一个新的"游戏"线程,并开始这一点。并调用它的中断,以阻止此游戏线程。

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.

线程是从gb_gameBoard,你会看到在构造函数的末尾创建,然后添加到 JFrame 中。这实际上是图形游戏板本身被添加到JFrame,它得到重新油漆使用其油漆()方法绘制板上的"活方块"的当前位置。

The GameBoard is a private class and it probably has too many responsibilities:

GameBoard 是一private class,它可能有太多的责任:

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.

它扩展了 JPanel,这意味着它是一个摆动图形面板(即绘制板)。它还实现不同的侦听器,这意味着它可以响应鼠标事件,并且它还实现了一个 Runnable,它是游戏线程本身。因此,GUI 事件线程可能运行于此类中,例如单击鼠标将导致 GUI 事件线程调用"mouseSthes()"方法。更改接口可能会导致 GUI 线程调用 paintComponent() 或组件Resized()方法。此外,还有一个 run() 方法清楚地实现此类中的另一个用户线程。查看此 run() 方法,了解它在做什么。

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.

确定问题并重构代码,使其不再引发此错误。这只需要几行代码才能更改。确保中断机制停止游戏仍然工作,虽然。

修复此 Bug 后...您应该能够长时间运行游戏,而不会产生堆栈溢出错误。

*** 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”


问题 1:描述导致此 Bug 的原因以及修复方式。


获取 Java 代码的副本并将其标记为"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!

任务 2:遇到并发问题。

现在应该很清楚,有两个线程通过 GameBoard 类运行。一个 GUI 线程,用于绘制正方形(并在鼠标事件上更改它们)以及更改板的其他方面(例如调整电路板大小时)。还有一个用户线程正在计算游戏中下一步的平方如何变化。似乎GameBoard类负责太多,它一定会在灾难结束!

The GUI thread repaints the board by calling:

GUI 线程通过调用以下调用重新绘制电路板:

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:

"并发修改异常"类型的捕获(然后忽略)表示我们在此处存在并发问题!在代码中添加"system.out.println"("!!!"),以查看是否确实引发过此异常:

} 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:

以每秒 20 帧的速度运行,随机方块数为 40% ...尝试通过单击它来更改板...或调整板大小...最小化并最大化它(导致调用重绘方法)。您尝试做的是导致显示"CONCONCONEXCEPTION !!!"消息。这并不容易,因为它要求GUI线程和游戏线程在访问或修改游戏方块方面发生冲突。但是,在游戏运行时按下鼠标按钮在电路板上绘制正方形时,我可以生成多个并发异常:

---

/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:

---但是你实际上会比这更糟。通过非常迅速地减少板的大小,而正在重新计算...您可以使用 ArrayIndexOutbounds 异常使用户线程崩溃:

/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!)

(使电路板成为整个屏幕的大小,然后以每秒 20 帧的随机平方开始运行。然后按图标的大小,使其回到其默认窗口大小...这几乎保证它会抛出这个例外!


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):

在运行时调整图形还会导致 GUI "AWT"线程崩溃,导致空指针异常,这很可能是由于并发问题(然后 GUI 已崩溃,即使程序的其余部分继续运行):

---

/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).

了解并发修改异常是如何产生的可能很有用。Brian Goetz 的书在第 82 页的第 5.1.2 节中对此进行了解释(尽管从第 79 页第 5 章的开始到第 5.3 节的阻塞队列和第 87 页的生产者-消费者模式值得阅读,以便获取上下文,并了解"复制"我们将使用第 5.2.3 节中的 OnWriteArrayList)。

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?

阅读 Brian Goetz 书的第 9 章 GUI 应用程序(第 189-202 页)以熟悉 Swing GUI 以及线程在 GUI 子系统中的工作方式可能也很有用。

将当前用于游戏板"状态"的阵列列表更改为使用并发 CopyOnWriteArray 列表对象。现在,您能否通过添加点和调整窗口大小来使系统崩溃?




*** 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).

问题 2:解释

CopyOnWriteArray 与普通 ArrayList 相比,其行为方式可能使所有这些并发问题消失(具体到代码中使用的特定机制如何以不同的方式与这两个类一起使用)。

*** 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!)

问题 3:在此处使用 CopyOnWriteArrayList 而不是普通数组列表可能有什么缺点?(假设我们并不担心并发问题!


*** Take a copy of your Java code and label it “ConwaysGameOfLife_VERSION2.java”

获取 Java 代码的副本并将其标记为"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.


任务3:加快挑战!

这部分更具挑战性,说明也不太详细。因此,您必须自己确定某些方面需要如何结构化,并担心您的代码是否线程安全。

我们首先想要计算完成 100,000 个电路板周期而不涉及任何睡眠所需的时间。


1.注释出 run() 方法中的睡眠语句,使其以最大速度运行。

2. 更改 run() 方法中的结构,使其执行 100,000 个电路板循环,然后自动完成。


3. 添加"日期"对象(或类似对象),以便打印出以毫秒为单位执行 100,000 个周期所需的时间。

*** 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!

问题 4:做五次运行,并写下您的系统执行 100,000 个生命游戏周期的不同时间(这些不会全部显示在屏幕上

由于代码中没有任何睡眠时间)。


现在,您可能有一个多核处理器,并且当前系统只使用单个内核,因为它对所有计算运行单个线程。

我们将重构代码,以便每个线程都计算共享板对象的一列。我们将使用执行器.newFixedThreadPool(4)执行任务(其中我们更改池中的线程数以查看它如何影响整体速度)。

在 GameBoard 类的顶部创建一个固定ThreadPool执行器,最初在池中包含 4 个线程。

重组将涉及当前 run() 方法,创建一个新的 Runnable 对象,对于它遍运行的每个"i",应将其称为"BladeRunner"。然后,每个"BladeRunner"对象将计算布尔的这一列游戏板 , 基本上在当前 run() 方法的中央"i"循环中执行代码。每个"BladeRunner"对象都将在线程池上排队,以便执行它们。

但是,如何知道当前 run() 线程(在 GameBoard 中)何时可以继续计算板的下一个周期?嗯...它应创建一个 CountDownLatch,其编号设置为要计算的列数(即创建的 BladeRunner 对象数)。然后,此整体线程将等待此闩锁,然后再继续下一个周期。然后,每个"BladeRunner"将在其运行方法的末尾对此闩锁执行单个 countDown(),以指示其已完成。因此,只有在为当前板计算所有列后,GameBoard 中的线程才会继续。

您的挑战是找出使此体系结构正常工作所需的细节,并担心并发方面 - 您可能需要在何处添加波动或同步?你应该在分析中准确无误,而不是到处添加易失性和同步!

*** Take a copy of your Java code with 4 threads assigned to the thread pool. Label the code: “ConwaysGameOfLife_VERSION3.java”



获取 Java 代码的副本,其中 4 个线程分配给线程池。标记代码:"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.

问题 5:试验线程池中使用的不同数量的线程(例如,尝试 1 个线程、2 个线程、4 个线程、6 个线程、8 个线程等)。每个

对于板的 100,000 个周期,时间记录三个(或更好的五个)毫秒的测量值。计算平均/标准偏差的时间,并产生一个表 /

图,以显示系统的最佳线程数。




*** 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 ***

请使用 Moodle 论坛询问有关此课程的任何问题 |

上传您的代码的三个版本,以及您的答案,以Moodle |


版权所有:留学生程序网 2020 All Rights Reserved 联系方式:QQ:99515681 电子信箱:99515681@qq.com
免责声明:本站部分内容从网络整理而来,只供参考!如有版权问题可联系本站删除。