Skip to content

Concurrency

Abhishek Khare edited this page Jun 23, 2017 · 20 revisions

Java Concurrency

Java Concurrency / Multithreading Tutorial

  • New, asynchronous "shared-nothing" platforms and APIs like Vert.x and Play / Akka and Qbit have emerged. These platforms use a different concurrency model than the standard Java / JEE concurrency model of threading, shared memory and locking. New non-blocking concurrency algorithms have been published, and new non-blocking tools like the LMax Disrupter have been added to our toolkits. New functional programming parallelism has been introduced with the Fork and Join framework in Java 7, and the collection streams API in Java 8.

Multithreading Benefits

  • Better resource utilization.
  • Simpler program design in some situations.
  • More responsive programs.

Multithreading Costs

  • More complex design: Though some parts of a multithreaded applications is simpler than a singlethreaded application, other parts are more complex. Code executed by multiple threads accessing shared data need special attention. Thread interaction is far from always simple. Errors arising from incorrect thread synchronization can be very hard to detect, reproduce and fix.
  • Context Switching Overhead: When a CPU switches from executing one thread to executing another, the CPU needs to save the local data, program pointer etc. of the current thread, and load the local data, program pointer etc. of the next thread to execute. This switch is called a "context switch". The CPU switches from executing in the context of one thread to executing in the context of another. Context switching isn't cheap. You don't want to switch between threads more than necessary.
  • Increased Resource Consumption: A thread needs some resources from the computer in order to run. Besides CPU time a thread needs some memory to keep its local stack. It may also take up some resources inside the operating system needed to manage the thread.

Concurrency vs. Parallelism

  • Concurrency - Concurrency means that an application is making progress on more than one task at the same time (concurrently). Well, if the computer only has one CPU the application may not make progress on more than one task at exactly the same time, but more than one task is being processed at a time inside the application. It does not completely finish one task before it begins the next.
  • Parallelism - Parallelism means that an application splits its tasks up into smaller subtasks which can be processed in parallel, for instance on multiple CPUs at the exact same time.
  • As you can see, concurrency is related to how an application handles multiple tasks it works on. An application may process one task at at time (sequentially) or work on multiple tasks at the same time (concurrently). Parallelism on the other hand, is related to how an application handles each individual task. An application may process the task serially from start to end, or split the task up into subtasks which can be completed in parallel.

Creating and Starting Java Threads

  • There are no rules about which of the two methods that is the best. Both methods works. Personally though, I prefer implementing Runnable, and handing an instance of the implementation to a Thread instance. When having the Runnable's executed by a thread pool it is easy to queue up the Runnable instances until a thread from the pool is idle. This is a little harder to do with Thread subclasses. Sometimes you may have to implement Runnable as well as subclass Thread. For instance, if creating a subclass of Thread that can execute more than one Runnable. This is typically the case when implementing a thread pool.

Race Conditions and Critical Sections

  • A race condition is a special condition that may occur inside a critical section. A critical section is a section of code that is executed by multiple threads and where the sequence of execution for the threads makes a difference in the result of the concurrent execution of the critical section.
  • com.edu.abhi.concurrency.threads.racecondition

Thread Safety and Shared Resources

  • Local Variables: Local variables are stored in each thread's own stack. That means that local variables are never shared between threads. That also means that all local primitive variables are thread safe.
  • Local Object References: Local references to objects are a bit different. The reference itself is not shared. The object referenced however, is not stored in each threads's local stack. All objects are stored in the shared heap. If an object created locally never escapes the method it was created in, it is thread safe. In fact you can also pass it on to other methods and objects as long as none of these methods or objects make the passed object available to other threads. see example (com.edu.abhi.concurrency.threads.sharedresources.SomeClass)
  • Object Member Variables: Object member variables (fields) are stored on the heap along with the object. Therefore, if two threads call a method on the same object instance and this method updates object member variables, the method is not thread safe.

Thread Safety and Immutability

  • We can make sure that objects shared between threads are never updated by any of the threads by making the shared objects immutable, and thereby thread safe. If you need to perform operations on the ImmutableValue instance you can do so by returning a new instance with the value resulting from the operation.
  • It is important to remember, that even if an object is immutable and thereby thread safe, the reference to this object may not be thread safe.
  • See Examples - com.edu.abhi.concurrency.threads.immutability

Java Memory Model

Java concurrency

Difference between Callable and Runnable interface.

Other Links

Clone this wiki locally