Today most programs have a concurrent element and knowledge of concurrency is vital. In this course Java Fundamentals - Concurrency with Multithreading, you'll gain the skills you need to create and work with such software using the Java libraries. This will also form a basis from which to learn more advanced frameworks. Just because this is a fundamentals course, it doesn't mean it's solely for Java novices. A wide range of topics will be covered, some fairly advanced, which are appropriate to more seasoned developers. First, you'll learn how to make a program multithreaded. Next, you'll learn how to safely communicate and share data between the threads and avoid liveness issues such as deadlock. Finally, you'll finish this course by looking at thread signaling and thread pools. After completing this module, you should be able to write multithreaded software with ease and be able to confidently discuss the subject in an interview situation.
David Flynn is a contractor working in the banking sector in London. David specializes in Java and Scala, with experience in C, C++, and Perl. When not working, he plays chess and is the server programmer of the Free Internet Chess Server.
Section Introduction Transcripts
Section Introduction Transcripts
Course Overview Hi there. I'm David Flynn. I'm an IT contractor specializing in the banking sector in London. Welcome to Java Fundamentals - Concurrency with Multithreading. Being able to write correct concurrent code is vital to many Java software engineers and one skill in this area will likely be tested in the interview. You want to be able to confidently discuss the topic as well as be able to apply the knowledge on the job. Whether you've just learned the Java language or have been using it a while and looking to improve your knowledge, or just to get a refresh, this course is for you. We'll get started with the thread class to create multithreaded programs. We'll then cover the Java memory model. Next we'll look at mutual exclusion and liveness issues before finally finishing with looking at thread signalling and thread calls. We'll cement in the knowledge with a number of small, but fun demonstrations. What we need to begin is a little experience with the Java language, but by the end, you'll be ready to write your own multithreaded applications and will have good knowledge of most of the major threading topics. I look forward to you joining me on Java Fundamentals - Concurrency with Multithreading at Pluralsight.
Understanding Threading and Concurrency In this module we'll cover some of the basic definitions and background knowledge that we'll need before starting to look at Java's implementation of threads. We'll define and differentiate concurrency, multitasking, and multithreading. We'll also cover some basic cache theory, which is important for understanding the issues with sharing memory between parts of a multithreaded program. In the technical interview, after the pleasantries of how the journey was, typically you're going to be asked some simple questions, possibly on definitions to ease you in. Even before then, definitions are relevant for phone screening interviews. Of course, it's only easy if you're able to define them. After reviewing this module, you'll be well placed to give answers to questions on these more general definitions and be ready to dive into the details of the Java threading libraries.
Creating and Managing Threads We've covered the basic background material to what concurrency is and what threads are. We're ready to get our hands dirty investigating some of the facilities Java provides and to start producing multithreaded code. In this module we'll look at how to start threads, monitor when they finish or die, see how to make them sleep, and how to interrupt them. We'll also cover a few other miscellaneous topics, handling uncaught and unchecked exceptions, thread local variables, plus a few items that are deprecated or unsafe to use.
Understanding Mutexes In the last module we saw how to share memory safely and avoid data races. Recall that data races are where unexpected values are being read from shared memory. If an execution order, that is the actual order that instructions are executed across all threads on a particular run, could impact data values and the problems would only show up occasionally or be difficult to track down. We saw that we could solve these problems by using volatile or publishing immutable data to threads. Is this the only worry we might have when writing a thread safe multithreaded program? No. There is another type of race called a race condition. This leads to inconsistent data structures being read and invariants broken and was mentioned briefly in the last module that volatile couldn't help us there. If we cannot use publishing immutable data to solve the problem, especially when more than one thread needs to write, we will have use mutual exclusion to ensure that only thread can access a so-called critical section at once. We'll see how the built-in synchronization that Java gives us can provide mutual exclusion and how it solves race conditions. Another use for mutual exclusion is when accessing resources where concurrent access where at least one thread is writing would lead to data corruption. There are other more advanced ways in Java to ensure mutual exclusion such as locks. Unfortunately, we don't have the time to go into those in this course. Once you've mastered this module and the next, you should be able to pick up the more advanced material should you need it.
Inter-thread Communication and Signaling So we've covered a lot of material so far. What we haven't done so much is interactions between threads aside from using shared state or publishing objects. We might need some kind of inter-thread coordination or signaling as in the following scenarios. We have no work for a thread to do, but we will do soon. We might need to supply the thread with some additional data in the middle of an operation, perhaps the response to a request the thread has made. Until that data is available, the operation cannot finish. We might need the thread to acknowledge that something has been received or that something has been carried out. In all these cases we want the thread to wait until a signal or a task arriving tells it it can now continue. We don't want to have to actively poll. We'll look at the built-in wait notify and NotifyAll methods on all objects, which are made for this purpose. We'll implement the simple producer/consumer model, which we'll improve on, eventually seeing that the hard work is now done for us in the BlockingQueue.
Thread Pools To complete the course, we need to cover one more important threading topic. Until now, we've been responsible for creating and maintaining our threads. What if an exceptional workload comes our way, which temporarily requires a few extra threads? Threads also have a nasty habit of throwing exceptions on us and exiting and if we don't notice, the capability to perform work will gradually degrade. On production systems we could be dealing with hundreds of threads, so it'd be ideal if Java could look after them for us. Well, it can via thread pools and this module will show you to use them, saving to have to write your own thread managers. This is more of an engine than the code we've been looking at before, but it's possible to extend it for customization if it doesn't do exactly what you need.