I'm writing an application in which some simulation is run in a SwingWorker. In this simulation some sets keep data which are modified in the doInBackground() method of the SwingWorker. This data needs to be shown by the GUI, but obviously this fails because as soon as the GUI starts accessing the sets a concurrent modification exception is thrown because the SwingWorker is modifying the same sets.
How would I go about sharing this data without the SwingWorker having to wait for the GUI to finish drawing the data? Do I have to copy the data and then publish() those? Won't this increase the amount of data by a lot (there is a lot of data)? Are there other ways around this problem?
Here's some simplified code:
public class World {
public Set<Foo> fooSet = new HashSet<Foo>();
}
public class Simulator extends SwingWorker<Void, Void> {
private World world;
private WorldPanel worldPanel;
public Simulator(World world, WorldPanel worldPanel) {
this.world = world;
this.worldPanel = worldPanel;
}
#Override
protected Void doInBackground() throws Exception {
while (true) {
doSomethingWithFooSet() //structurally modifies the set
publish();
}
}
#Override
protected void process(List<Void> voidList) {
worldPanel.repaint();
}
}
public class WorldPanel extends JPanel {
private final World world;
public WorldPanel(World world) {
this.world = world;
}
#Override
public void paintComponent(Graphics g) {
drawWorld() //reads from fooSet in world
}
}
Don't get me wrong, I understand why this doesn't work, I'm just wondering what I should change in this design to be able to do what I want to do: access the same data that my simulation is modifying. Does process() run on the EDT? If so, would it be possible to let process() update the sets in a copy of the world object which the WorldPanel uses to draw the data?
You cannot simultaneously update and display the world object, so you have two ways out: do update and displaying sequentially, or clone data so that updated and displayed data are different. To implement the first variant, just do not use SwingWorker. In the second variant, if simple cloning the whole world is unacceptable, let the background thread compute not just the new state of the world, but also commands to modify the world's image. Publish that commands and then process them to update the picture.
I would add a flag in the gui, wether it shall show/access the data or not
initially set it to false and when your worker finishes reload the accessing part with switched flag
Related
I need to generate a new Thread every 2 seconds. So I tried to use the Timer class in the main(String[]) method but my program just exists after the milliseconds I specified in the Timer constructor.
Program.java:
public class Program
{
private static int panelWidth;
private static int panelHeight;
private static MyPanel panel = new MyPanel();
public static void main(String[] args)
{
MyFrame frame = new MyFrame();
frame.add(Program.panel);
Program.panelWidth = frame.getWidth();
Program.panelHeight = frame.getHeight();
Timer generateBallTimer = new Timer(2000, new GenerateBalls());
while (true)
{
generateBallTimer.start();
}
} // End of main method
/**
* Generate a new ball every 2 seconds.
*
*/
public static class GenerateBalls implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
Program.generateBalls();
}
}
public static void generateBalls()
{
// Generate a ball each 2 seconds
while (true)
{
Program.panel.balls.add(new Ball(Program.panel));
}
}
} // End of program class
If in the Timer constructor I will specify 3000ms my program will be closed after 3 seconds and so on.
What am I doing wrong here?
Can you give me example of that "display list"?
You talk about "balls". What does your program need to know about a ball? Probably its position, maybe its speed, maybe its mass. Size? color? other stuff? It's up to you. The simplest implementation of a Ball object would just be a class with public fields to hold all of that information. Then, if Ball is the only kind of moving object in your animation, then your display list could just be a List<Ball>.
In a more complicated program, your Ball class might be an extension of some more general class, maybe VisibleObject, and then your display list would be a List<VisibleObject>.
As far as I know,for all the objects in a game to work concurrently they need to be Threads.
In a sense, you are right because there is only one class in all of Java that can do any work at all, and that class is Thread. No other class actually ever does anything. Other classes merely define methods that can be called by threads.
The trick is, to decouple the threads in the program from the work that they do. That's the motivation for the Runnable interface. Instead of having one object that both is a thread and also, describes the work to be done by the thread, you can have two classes; One takes care of all the thread-y stuff (.start(), .interrupt(), .join(), ...), and the other describes the work to be done (.run()).
Some say, it's hard to write a program that has too many classes/objects, but it's easy to write one that has too few.
As long as your Ball objects or your VisibleObject objects cleanly describe the things that you want to see on the screen and the ways in which you want to see those things move, there's no reason why each one's methods must be called by its own dedicated thread. There's no reason why you can't have just one thread that does the calculations for each one in its turn.
I've written a program which displays balls in a window which are moving and which absorb each other with a certain probability when getting in contact.
The current version works, the balls's movement is been calculated every time the paintComponent method is (implicitely) invoked:
public class ColliderPanel extends JPanel {
...
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// calculate balls's movement
Random r = new Random();
ListIterator<Ball> it = cp.getColliderPanel().balls.listIterator();
Vector<Ball> ballsToRemove = new Vector<Ball>();
while (it.hasNext()) {
Ball b = it.next();
b.move(1.0 / 60.0);
b.collideFrame(cp.getColliderPanel().getSize());
ListIterator<Ball> it2 = cp.getColliderPanel().balls.listIterator(it.nextIndex());
while (it2.hasNext()) {
Ball b2 = it2.next();
if (b.collide(b2)) {
if (r.nextDouble() < 0.5) {
if (b.m > b2.m) {
b.swallow(b2);
ballsToRemove.add(b2);
} else {
b2.swallow(b);
ballsToRemove.add(b);
}
}
}
}
}
cp.getColliderPanel().balls.removeAll(ballsToRemove);
try {
Thread.sleep((long) (1000.0 / 60.0));
} catch (InterruptedException e) {
e.printStackTrace();
}
for(Ball b : balls) b.draw(g);
repaint();
}
...
}
Now I want to outsource the calculation of the balls's movement to a second thread. I tried to create another class SimulateBallsMovement implements Runnable which does the calculation in the overriden run method and created a new Thread in ColliderPanel, which has SimulateBallsMovement as Runnable-object.
public class ColliderPanel extends JPanel {
private Thread simThread = new Thread(new SimulateBallsMovement());
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// calculate balls's movement
// what to to here? how to synchronize the painting and the calculation?
for(Ball b : balls) b.draw(g);
repaint();
}
...
}
My problem is that I don't know how to synchronize the painting of the balls and the movement calculation? Does ColliderPanel even need the Thread as a member? I just found tutorials on how the synchronize two threads which invoke the same method, but what do I want to do here?
The main thing to remember with Swing is that almost none of the Swing methods should be called from any other thread except the Swing Event Dispatch Thread (EDT).
The EDT is what sits in a loop, waiting for key presses, mouse clicks, and other events, and calling your handlers each time an event happens that interests your program.
Whenever any of your other threads wants to do something that will affect the GUI, it should call the SwingUtilities.invokeLater(r) method where r is some Runnable object. The invokeLater(r) method will post an event containing r to the event queue, and the EDT will handle the event by calling r.run(). The r.run() method can then safely call whatever Swing methods you need it to call.
This looks like classic producer consumer scenario. The thread which calculates ball movements is producer and the thread which paints them is consumer. Check out these tutorial on the topic: http://www.tutorialspoint.com/javaexamples/thread_procon.htm or https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
One suggestion is to move the calculations into a swingworkers background processing method and calling repaint in done method of the worker.
To simplify the use of the AWT thread mechanism, and async component data fetching and component enable/disable while loading data, I wrote the ComponentUpdateThread, a long time ago. It makes it terribly easy to do updates of data and get the right things done in the right thread context.
https://github.com/greggwon/SwingUtil/blob/master/java/main/src1.5/org/wonderly/swing/ComponentUpdateThread.java
new ComponentUpdateThread( button1, button2 ) {
}.start();
is the basic premise of how you use it. All listened components will recursively be traversed and disabled by the actions of start(). There are three methods that you can implement.
The first one, setup(), is invoked by an AWT event thread, and should do anything to components (aside from disabling things that the cons parameters will make happen). This maybe simple things like emptying a list model etc.
The construct() method is invoked by an async, random thread. This method should "go get the data" to be used to populate controls, and put it into an appropriate container structure that it will return.
Finally, finished() is invoked by an AWT Event thread after construct() returns, and it should call getValue() to get the returned value from construct() activities, and then push that data into models/components as appropriate. finished() needs to call super.finished() at the right moment to "enable" the components passed into the cons. You can then disable things conditionally such as last selection in a list, options in checkboxes etc, and then return.
Here's an example of these methods taken from the javadocs. This shows the use of older APIs and doesn't include the fact that with generics, you can now make construct() a generic method with getValue() returning the same type. I have a version of this code that does all kinds of things that have been added more lately into Java.
This code is just to demonstrate the concepts around separation of thread use into separate methods so that you don't have to use SwingWorker directly, all over the place, but can use a more generic mechanism such as this.
My latest version of this code, includes the ability to chain together and next invocations so that more complex data retrieval and population can occur.
Ultimately, it would be really nice to just provide a ModelUpdater class that you could provide the component and any related model details to so that there was a compartmentalized use of data sourcing from remote access mechanisms.
public void setup() {
super.setup();
list.setEnabled(false);
list.clearSelection();
}
public Object construct() {
try {
Vector v = remote.getData();
Collections.sort( v );
return v;
} catch( Exception ex ) {
reportException(ex);
}
return null;
}
public void finished() {
try {
Vector v = (Vector)getValue();
list.setListData(v);
} finally {
super.finished();
list.setEnabled(true);
edit.setEnabled(false);
del.setEnaled(false);
}
}
I have a code with two methods.
public void fondo() { ... } //Gathers JFrame Background and system time
public void recuperarDatosInternet() {...} //Connects to a URL and gets data.
When the JFrame is running, at the beginning it takes four or five seconds to perform all the operations of those methods.
While it's loading, the frame displays totally empty for 3 or 4 seconds until all the methods are complete, then the frame shows up and it's all right.
How can I make a Progress Bar that shows the user that something it's loading?
I don't mean a ProgressBar that are predetermined to take "4000 ms". I am referring to a progressbar that can take whatever it takes, and the bar doesn't reach the 100% until the methods are complete.
You could use a SwingWorker for this. This class enables allows the time-consuming work to be done in background thread and does not hold up the user-interface in the meantime. It also has the facility to divide the work up into 'chunks' and to update the user-interface on the completion of these chunks of work. This is what you would need for a progress bar, although it depends on your task being 'chunkable'. The link above takes you to the JavaDoc for this class which contains an example for both the simple and the 'chunked' usage.
If you run heavy task in The Event Dispatch Thread it's gonna to freeze until finish to avoid that you can execute the download in another thread using SwingWorker.
Follow this link to see a complete example with progressBar , special attention to setProgress() publish() and process().
Example:
public class MyWorker extends SwingWorker<Integer, String> {
#Override
protected Integer doInBackground() throws Exception {
// Start
publish("Start Download");
setProgress(1);
// More work was done
publish("More work was done");
setProgress(10);
// Complete
publish("Complete");
setProgress(100);
return 1;
}
#Override
protected void process(List< String> chunks) {
// Messages received from the doInBackground() (when invoking the publish() method)
}
}
and in client code:
SwingWorker worker = new MyWorker();
worker.addPropertyChangeListener(new MyProgressListener());
worker.execute();
class MyProgressListener implements PropertyChangeListener {
#Override
public void propertyChange(final PropertyChangeEvent event) {
if(event.getPropertyName().equalsIgnoreCase("progress")) {
downloadProgressBar.setIndeterminate(false);
downloadProgressBar.setValue((Integer) event.getNewValue());
}
}
}
I'm making a game in android using opengl-es, using multiple threads:
class World{
protected static final AtomicInteger entityLock = new AtomicInteger();
private GameEntity entities[];
public World(){
// populate game world with entities
// executed on main thread
addEntity(new GameEntity("tank"));
addEntity(new GameEntity("rifleman"));
addEntity(new GameEntity("rifleman"));
}
void update(){
synchronized(entityLock){
for(int i = 0;i<entities.length;i++){
// move entity to new position
// executed on PhysThread
entities[i].updatePosition();
}
}
if(entity.isDead(){
// remove entity. Enter sync block inside removeEntity() method
removeEntity(entity);
}
}
void draw(GL10 gl){
synchronized(entityLock){
for(int i = 0;i<entites.length;i++){
// draw models
// executed on GLThread
Vector3 entityPosition = entities[i].getPosition();
gl.glTranslatef(entityPosition.x, entityPosition.y, entityPosition.z);
entities[i].draw();
}
}
}
public void addEntity(GameEntity entity){
synchronized(entityLock){
// arrays stuff
}
}
public void removeEntity(GameEntity entity){
synchronized(entityLock){
// arrays stuff
}
}
}
class MyRenderer implements GLSurfaceView.Renderer{
World world;
public MyRenderer(World world){
this.world = world;
}
public void onDrawFrame(GL10 gl) {
// executed on GLThread
world.draw(gl);
}
}
class PhysThreadRunnable implements Runnable{
private long tickRate = 30;
private World world;
private PhysThreadRunnable(World world){
this.world = world;
}
protected void setTickRate(long tickRate){
this.tickRate = tickRate;
}
public void run() {
while(true){
try {
// executed on PhysThread
world.update();
Thread.sleep(1000/tickRate);
} catch (InterruptedException e) {
return;
}
}
}
}
MyActivity extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
World world = new World();
// sets up the game world, populates it with entities
// set up GLSurfaceView (simplified)
setContentView(R.layout.main);
GLSurfaceView mGLView = findViewById(R.id.myGLSurfaceView);
mGLView.setRenderer(new MyRenderer(world));
// start phys thread
PhysThreadRunnable physThreadRunnable = new PhysThreadRunnable(world);
Thread physThread = new Thread(physThreadRunnable);
physThread.start();
}
}
I have a problem where sometimes (but not every time) when I start the game, the PhysThread gets stuck waiting for the lock to be released (i.e. when I go to debug and pause the thread, it is just sat on synchronized(entityLock) inside update()
What's really strange is that after a while (between 2 seconds and a minute), the PhysThread will be unblocked, and the game will continue without either thread getting locked out for more than a few iterations of the thread loops. (i.e. the game runs fine)
Edit: I added some extra stuff to the example, just in case that is the cause of the problem. Basically, updating and drawing an array of entities rather than a single entity
I think the issue here is probably that there is no fairness guaranteed by the 'synchronized' block.
The OpenGL thread will always be rendering continuously, so it will attempt to reenter onDraw as soon as it finishes it. Since the choice of which thread is allowed to enter the synchronized block is arbitrary, it could be possible that the OpenGL thread attempts to reacquire the lock before it is released to the physics thread, and based on some arbitrary criteria it is given the lock over and over without allowing the physics thread to enter.
This might explain why it happens sometime and not others, since it is an arbitrary decision.
You might try implementing a fair lock instead of a synchronization block, or making it such that the OpenGL does not attempt to redraw the scene more than once since the last physics update (put the render thread to sleep until an update has occured).
In the end, I went for the cheat solution. I put the synchronization blocks around access to the entities array and put the for loops inside a try/catch with ArrayIndexOutOfBounds:
void update(){
try{
for(int i = 0;i<entities.length;i++){
GameEntity entity = entities[i];
synchrnonized(entity){
entity.updatePosition();
}
}
}catch(ArrayIndexOutOfBoundsException aioob){
if(tryAgain){
update();
} else {
return;
}
}
}
The problem with this solution is that if entity.updateposition() throws an ArrayIndexOutOfBoundsException from something completely unrelated, then I'll catch it and misinterpret it. Plus the whole thing is a bit messy, and once in every while, a frame or update gets skipped
As this appears to solved the problem, I suspect the original cause probably lies somewhere deeper in my code, between entering the for loops and actually modifying the entities, and I don't really think it'd be fair to dump my entire code here.
I'll leave the question unanswered for a couple days in case anyone else has a better solution
I'm building a Swing application and one part of the functionality should be to process and output some text visually and audibly (using Mary TTS). I need some advice on the best way for the GUI and text processing classes to communicate.
The GUI class is a subclass of JPanel. Within that I have a class implementing Runnable, called LineProcesser, which prepares the text to be dispatched to an audio player. I'm using a thread executor to keep this off the EDT (that may not be the best way but it seems to achieve the result I'm after).
My intention is for LineProcessor to run through all the text and update a JTextArea at the end of each line. Additionally it will need to halt and wait for user input at certain points. After the user input has been completed the GUI class should tell it to resume processing.
The following code illustrates what I currently have:
public class MyPanel extends JPanel {
ExecutorService lineExecutor = Executors.newSingleThreadExecutor();
Runnable lineProcessor = new LineProcessor();
public class LineProcessor implements Runnable {
private int currentLineNo = 0;
public LineProcessor() {
// ...
}
#Override
public void run() {
// call getText();
// call playAudio();
currentLineNo++;
}
}
}
private JButton statusLbl = new JLabel();
private JButton mainControlBtn = new JButton();
private void mainControlBtnActionPerformed(ActionEvent evt) {
if (mainControlBtn.getText().equals("Start")) {
lineExecutor.submit(lineProcessor);
mainControlBtn.setText("Running");
}
}
}
How can LineProcessor notify GUI components that they need to change and how can it be paused and restarted from within the GUI? I'm confused as to whether I need a Swing Worker, property/event listeners or something else? The examples I've read sort of make sense but I can't see how I can apply them to the code I have here.
All you need to do is wrap any Swing calls in a Runnable, and queue it on the EDT via SwingUtilities.invokeLater(myRunnable);. That's it. No need for a SwingWorker.
e.g.,
public class LineProcessor implements Runnable {
private int currentLineNo = 0;
Runnable LineProcessor = new LineProcessor(); // won't this cause infinite recursion?
public LineProcessor() {
// ...
}
#Override
public void run() {
// call getText();
// call playAudio();
currentLineNo++;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// *** Swing code can go here ***
}
});
}
}
You will have to use both SwingWorker and Event methodology.
Place your long running code in Swing Worker.
Create new property change Event, listener, manager
In your SwingWorker, when the change event occurs, call PropertyChangeManager to notify all the liseners.
All GUI components which wants to be notified with the event should register themselves with the PropertyChangeManager.
Your PropertyChangeManager will call customProperyChange method of the PropertyChangeListener and will pass the properyChangeEvent
What you are looking for is a SwingWorker. This class allows to perform the work on a worker thread, having periodical updates on the EDT, and in the end update the EDT as well.
Several examples are available on SO and in the Swing tutorials. Just a few links
The 'How to use progress bars tutorial', which happens to update a text area as well
The 'Concurrency in Swing' tutorial, a must-read if you start with SwingWorker
The SwingWorker javadoc
Reporting progress can be done with the publish method, these results will be passed to the process method in which you can update the UI. At the end, the done method is called allowing you to perform some final UI updates.
For the pause/restart functionality ... you can use an invokeAndWait in the doInBackground method with a blocking method call (for example showing a JOptionPane asking for user input). But if you start using invokeAndWait in the doInBackground it might be overkill to use the SwingWorker and you can simply opt for the approach #Hovercraft Full Of Eels suggested