1

I am trying to write a multi-thread program with Swing. Essentially how the program works is that when it runs it will have a robot(represented by a circle in screenshot) that is wondering around in a field. This robot should be controlled by a thread of it's own. The program has a button "Launch Robot" that will create another robot on the field(upto a max of say 10). Right now I have the basics of the program, but it all runs under one thread. I can launch as many robots as I want but they all run under a single thread. But I want that whenever I click "launch Robot" an independent thread be created and control that robot. This is how the program looks right now: enter image description here

The UML diagram for the program is as following: enter image description here

Since its a bit long I won't post the whole program. But the method that starts and updates the robots(currently controlling only one robot on the field) is as follows:

    public void gameStart(){
    Thread gameThread = new Thread(){
        public void run(){
            while(true){
                //execute one time step for the game
                gameUpdate();
                
                //refresh screen
                repaint();
                
                //give other threads time
                try{
                    Thread.sleep(1000/UPDATE_RATE);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    };
    
    gameThread.start();
}

My question is how can I achieve multi-threading for such a scenario? I know the basics of SwingWorker, but since I haven't done any multi-threading, I have no idea on how to make several threads work and be updated by one thread(update position of robots that are controlled by threads).

EDIT: Just to make my point, this is a project that I am working on. It's not about if multi-threading makes sense in this scenario or not.

Community
  • 1
  • 1
aaa
  • 435
  • 8
  • 22
  • I wouldn't. For each new `Robot` you create, you'd be creating a new `Thread` and this will not scale well. A better solution would be to use the `gameUpdate` method to iterate over a `List` of `Robot`s and run through their update logic and the schedule an update of the screen – MadProgrammer Nov 25 '15 at 03:48
  • @MadProgrammer I updated the question to reflect that fact that this is a project that I am working on. So it's a requirement that I implement it the way I described it. – aaa Nov 25 '15 at 03:52
  • Here's a problem then, Swing is single threaded, you have a single point at which painting must be done, if the robot is updating it's position when Swing wants to paint, you run the risk of a dirty update. You question doesn't make sense. If you have a `Thread` controlling each `Robot`, then why do you need to coordinate them? Just let them run and do there thing. You're really problem is getting them to render – MadProgrammer Nov 25 '15 at 03:55
  • @MadProgrammer ok (1) how do I do that? (2) what if i wanted the robots to avoid each other? how can they communicate? (3) can swing do this? or if it's not suitable for this kind of multi-threading application, what would be a better alternative? – aaa Nov 25 '15 at 03:57
  • Collision detection would be problem, by the time you checked for a collisions, any of the robots could have moved through you, as they are updating independently. It's not an issue with Swing, as just about any GUI framework will have the same problem, just about all of them are single threaded. To your second point, what do you want them to say? Just by asking the question suggests that you need to keep track of `Robot`s in some meaningful way, but your introducing race conditions and risking deadlocks – MadProgrammer Nov 25 '15 at 04:06
  • One possible solution would be to use monitor locks on your critical paths, like painting and collision detection, so that non of the `Robot`s can update them selves while these operations are running – MadProgrammer Nov 25 '15 at 04:07

3 Answers3

3

Create a RobotModel that contains a Collection<Robot> and defines their interaction. Iterate the model in the doInBackground() implementation of a SwingWorker. Invoke publish() as meaningful events arise, and process() updates to the RobotWorld view by querying the model. As discussed here, there should be no drawing in the model and no interaction logic in the view. A single worker should suffice for a moderately complex model, but you can synchronize multiple workers as shown here.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
1

A good option to achieve this is to use ScheduledThreadPoolExecutor.
Instantiate the thread pool via:

ScheduledThreadPoolExecutor threadsPool = new ScheduledThreadPoolExecutor(size);

To create a new Robot Thread, use:

    threadsPool.submit(new Runnable() {
        @Override
        public void run() {
            launchRobot();
        }
    });

This way, each invocation will instantiate a new Thread.
You can set the limit of the total number of allowed Thread via the "size" argument.
You can also pass a result after each thread completes using:

public <T> Future<T> submit(Runnable task, T result) 

If you want less detail, you could let Java do the work for you with the following convenience API:
Executors.newCachedThreadPool() (unbounded thread pool, with automatic thread reclamation) or:
Executors.newFixedThreadPool(int) (fixed size thread pool)

Remember us, Executor. Remember what was done here today. And may Adun watch over you

Community
  • 1
  • 1
Leet-Falcon
  • 2,107
  • 2
  • 15
  • 23
  • How would you deal with collision detection? How would you prevent possible race conditions when the UI is been updated? – MadProgrammer Nov 25 '15 at 07:37
  • @ MadProgrammer UI updates should always be called on EDT thread regardless of number of threads. One good approach is to use SwingWorkers or at least invokeLater() and synchronize by the application critical regions – Leet-Falcon Nov 25 '15 at 09:09
  • Absolutely, but how would you resolve the potential race condition between the multiple threads and the UI trying to paint their states – MadProgrammer Nov 25 '15 at 09:11
  • Maybe a workaround in form of ordered resource coloring. Each has a foreground priority (or z-order value). Some will simply hide others when the UI collides. – Leet-Falcon Nov 25 '15 at 09:25
  • But if the state of each not is changing, independently of the code which is painting/checking collisions how would you prevent the possibility of race conditions. Look an executor service isn't a bad idea, but the question has such a wide breadth it there are more things that need to be considered which you haven't covered :P – MadProgrammer Nov 25 '15 at 09:43
  • Sure, I agree. OP wanted to experiment so it's a good option to start with. – Leet-Falcon Nov 25 '15 at 10:41
  • So, you gave them the spade and are just going watch them dig themselves into a hole :P – MadProgrammer Nov 25 '15 at 10:48
  • A thread pool could be used inside the model; you're both right about the need to notify any listening view on the EDT; note that `SwingWorker` implements `Runnable`, `Future` and `RunnableFuture`; a simple elastic collision model is cited [here](http://stackoverflow.com/a/24923301/230513). – trashgod Nov 25 '15 at 11:13
1

This robot should be controlled by a thread of it's own.

Why?

IMO, the most important way to describe any thread is to say what it waits for. In an internet server, an accept thread waits for incoming connections from new clients, and a client thread waits for additional commands from a single client. In a program that performs massive parallel computations, a worker thread waits for tasks to be performed. In a GUI program, the event dispatch thread waits for keyboard and mouse events. Etc., etc.

What will your robot thread wait for?

If it waits for time to pass (i.e., if it calls Thread.sleep()), then your GUI framework probably already has a timer thread that does that, and you might want to consider using it. (In Swing, you would use the javax.swing.Timer class to submit new timed tasks.)

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57