Saturday, 22 October 2011

Java: Concurrency with Threads: Using Threads

Yay, I have a cold! Luckily, tomorrow is my day off. There's a lot of tech detail I'm getting through before it comes to the examples, but I paraphrase a lot, so hopefully I can squeeze all (or most) of it in today, meaning at the start of the new week, we can delve into actually playing around with stuff again!

Back to threads, a thread of control is just a single path of execution through a program. So, for all the programs we've looked at and fiddled with, we had 1 thread, which started in the main method, and ended with the program.

Every program has 1 thread when it begins running (the main method), but in this method, we can call further threads, and those can make threads of their own etc. as needed by the application. Normally, you'll want your main thread to do all the real work, with other threads sitting there to monitor incoming connections or whatever.

Java, of course, provides full support for threads which are integrated into the language as well as class libraries.
The class, as you might guess, is Thread. A new thread is started by calling this object, which will start up and manage the new thread for you. This thread, once running, can call the methods of any objects it has access to within the same program.

A number of important methods are provided by the class, such as run, which is an equivalent of main(), with the exception that it takes no parameters.

TL;DR: Thread class is used for threads. Programs start with 1 thread (main) which can call more threads as needed, limited only by the processor power of the computer.

Synchronization
All threads created within a program are part of that same program, so they can potentially access any object in that program which a reference is available for. Haphazardly using this can lead to some issues. What happens if 2 threads are using the same object at the same time?

Example: (I think I'll color code stuff more often!) ThreadOne and ThreadTwo are using the same Queue method. Both call add at the same time. Both will add, but on the same Queue. So let's say the queue had 0 objects at first. Both threads call add on the empty queue, so what's the end result? 


Well, this depends entirely on the order of commands. Since its impossible to be 100% certain of the order in which the commands are executed, we're left with what's known as non-determinacy. Which spell-check tells me is a load of bull. The end result of the queue varies from both being added (in what order, though?), or both items are added to the same location (one value would be overwritten).
TL;DR: Unless you safeguard your methods, shit can go very wrong. You cannot be 100% sure of the order things happen in, and multiple threads accessing the same object or structure could result in data lost.

The issue then is, as far as the threads are concerned, nothing wrong's happened, but now we've lost data. The solution is for us to introduce mechanisms for the add() method to coordinate threads. We need to make our method thread safe (at least if we intend it to be used in a  multi-thread program).

Java provides us with monitors for this kind of thing. These are high-level mechanisms for ensuring only 1 thread at a time executes a critical region of code. The code specified as a critical region is guaranteed by the monitor to be executed, start to finish, by one and only 1 thread at any time. Another thread trying to mess with this critical region while its in use is blocked until the first thread is done with its business. The implementation of monitors is enabled by locks on objects. Locks aren't meant to be micromanaged by the programmer, so instead, we use the synchronized keyword in method creation.
TL;DR: The solution, or the method of safeguarding, lies in using the keyword synchronized. This creates monitors and locks etc behind the scenes that ensure for all synced methods, only 1 thing happens at a time, and other threads waiting to do stuff must wait, so stuff doesn't screw up.

To call a synchronized method, the thread needs to obtain the lock on the object the method is being called for. If unavailable, the thread must wait.

You can apply this to statements too, but unless we come across it, screw it, not important enough to describe in detail.

When using synced methods or statements, there's a couple of things that can go wrong, one of which is known as deadlock. This would occur if 2+ threads are holding locks, but also waiting to obtain a lock held by another thread.  Just letting you know!

There's only 1 more short section on the technical details, but it's short, and the above was comprised of 3 anyway! Anyway, that's all for now. Questions welcome! Comments, too!  Follow, subscribe, share etc, on Monday!

And as part of a shameless plug for a friend, if you're interested in classic movies/books/music, visit his site here (fixed), and feel free to throw loads of criticism at us. 

5 comments:

  1. I had to go back and read the intro, I keep forgetting the premise of threads.

    ReplyDelete
  2. Yeah, they're a little long, and mostly not as important as actually getting practice in. At least the come in handy when stuff does go wrong!

    ReplyDelete
  3. So interesting!

    ReplyDelete
  4. As I have voted for 'other' I want you to program a remake of Custer's Revenge. And I stress all other voters to vote other along with me.

    ReplyDelete
  5. Yeah these kinds of problems happen a lot more when you're programming at night for some mysterious reason.

    Get well soon, I think I'm just starting to get better myself.

    ReplyDelete