Concurrency Fundamentals
What is Concurrency?
This blog post aims to simply explain the meaning, function and importance of concurrent programming.
Luckily, concurrency is a lot easier to understand than it's name sets out. Basically, it explains a system or program's ability to 'multi-task', or at least give the impression of doing so. You see, a computer never actually does more than one task at a time but instead jumps between running pieces of each task, so quickly that it seems simultaneous.We have all used a computer for many things at once, just this morning I was sending e-mails, listening to music, writing this blog... and then some. So how does the computer manage to do all things things at seemingly the same time? By loading processes into
The two most basic units of concurrency are processes and threads. Processes operate on the program level while threads operate on the process level. This is due to the fact that processes are themselves made up of threads. To create a thread in Java we can either extend the Threads class or we can implement the Runnable interface on a class of our choosing.

When a thread is of low priority and runs in the background, it is called a daemon thread. Daemon threads are also known as service provider threads in Java as they depend on user threads in a process. To create a daemon thread in Java we simply use the setDaemon() method which returns a boolean of either True or False depending on if the thread is a daemon or not (by default the initial value is False)
The Java Memory Model (JMM) is a memory model that defines the behaviours between a multi-threaded Java code and the shared memory these threads have access to. It is a blueprint for how the processor and memory subsystems operate for maximum performance.
In a multiprogram environment, more than one process will compete for a finite set of resources and if said resource is not presently available, the process will have to wait for it. This waiting for resources leads to 3 possible scenarios: deadlock, livelock and starvation.
A deadlock is a situation in which processes block each other due to other processes using the needed resources and none of the processes makes any progress as they wait for the resource held by the other. A livelock is similar to a deadlock and occurs when 2 or more threads continuously switch between states, between themselves (rather than waiting like in a deadlock). Both of the deadlock and livelock situations result in the threads not being able to perform their respective tasks.Starvation is an outcome of a process and occurs when a process is unable to gain regular access to the shared resources it requires to complete a task and is therefore unable to make any progress.
When creating a thread in Java it is very important to override the Thread classes run() method, if we don't do this, the program will by default execute the run() method from the Threads class which is empty and will therefore cause no output for our chosen thread.
Similar to Java's Collection framework which allows functionality for collections in Java, Java's Concurrent Collection API's are a collection of classes and methods that are designed for working with threads and multi-threaded processes in Java (concurrent operations).
Atomic operations describe operations that always execute together, either all of them execute together, or none of them do. This is important in cases where one thread is reading and updating a variable (say a count, like i++) that is needed by the next thread. Because thread A reads and then increments the counter, thread B will be faced with the incremented number instead of the original starting point of the count. To avoid this problem we can make use of Atomic classes to ensure each thread is confronted with the same value for said variable. To use Java's atomic classes we need to import the java.util.concurrent.atomic package and some of the most commonly used Atomic classes are AtomicInt, AtomicLong, AtomicBoolean and AtomicReference (which can be implemented for any type of object).
Java's Executor framework provides the classes Executor and ExecutorService which allow 'thread pool' facilities to Java applications. Instead of creating a new thread each time (which will put strain on the CPU and operating system), thread pools allow tasks to be executed in parallel. This improves the response time of an application as well as helping to avoid 'exhaustion' errors like running out of memory. The difference between the Executor and ExecutorService classes is that the Executor class is the core interface (parent class) and is an abstraction level for the execution of threads in parallel. The ExecutorService class is an extended interface (child class) of the Executor class and it provides more functions including shutting down the thread pool and the ability to return a Future object (used to check the status of a thread).
Comments
Post a Comment