To wrap up our discussion of threading and concurrency, let’s take a look at some of the other types that Java provides that helps us out with concurrency. First let’s look at some of the collections and what the issues are there. Now one of the things we need to look at is how do we safely access collections when we’reworking on a concurrency, and then there’s the issue of blocking collections. So let’s first look at this idea of concurrency safe collection access. Java provides what are called synchronized collection wrappers, and the issue is that most collections are not thread safe. So what that means is if you do something that creates a list or a map, and you start modifying that on multiple threads at the same time, at some point you will corrupt that list or map. So we need a way to work with that in a thread-safe way. Now we could write out that code manually, but we don’t have to do that. Java provides what are called thread-safe wrappers for collections. So the collection class has a series of static methods that all us to create these thread-safe wrappers. That’s like synchronized list, or synchronized map, and so forth, and what’ll happen is that we create the list or the map as we normally do, but when we pass it in to these static methods, what we get back is a wrapper that is thread safe. So what that means is that all the actual collection work occurs in the original collection, but as long as you access the collection through the thread-safe wrappers, the wrappers will make sure that all the necessary thread coordination occurs. So we don’t have to worry about those kinds of details, and since we work with collections so often, it’s really helpful to be able to use those thread-safe wrappers when we need them. Now the other side of the issue is blocking collections, and these address something called the producer and consumer model. Now the producer and consumer model is this idea that you have one or more threads that are producing some kind of content that needs to be worked on, so maybe they’re reading something from a file and putting theminside of an object, something like that, and then one or more other threads that consume that content, so in other words they have to do the actual work. And as long as producers stay ahead of consumers, life is fine, but if a consumer comes back for work, and there’s no work there, then the consumer has to wait for that work to be available. Well to help us with that, Java provides blocking queues. What that allows us to do is have the producer put content into the queue as it normally does. A consumer can read content from the queue as it normally does, but if the consumer comes back and there’s no content there, the consumer will block until there’s some content available, then as soon as there is content available, the consumer wakes up and then can carry on. And there’s a few of these available. There’s a LinkedBlockingQueue, which just uses a link list as a queue, there’s also a PriorityBlockingQueue, which allows us to put a priority algorithm in place so things come out of the queue based on some priority order opposed to the order they go in there. And there’s still so much more. There’s a couple of key packages that provide other types that we might want to use with concurrency. Now one of the packages is java.util.concurrent, and that contains most of thegeneral types for working in concurrent situations, and honestly it has many of the types that we’ve talked about throughout this module, things like the callable interface, things like the runnable interface, things like the Executives class, they’re all part of that java.util.concurrent package. But it also has types for more advanced scenarios, things like semaphores. Semaphores are a concurrency object that allow us to have multiple threads access resources, but on some limited level, like we could have up to three threads working at one time, but not more than three, that sort of stuff. And there is just so much more inside of there, so if you’re doing a lot of concurrency work, that’s a package you’ll want to check out. Another important package is the java.util.concurrent.atomic package, and that contains types that provide atomic operations, things like atomic integer, atomic Boolean, and with those there are methods like set and get that are atomic, in other words, the set and get are safe, but also more advanced things like getAndAdd, so that you can actually get the current value of an atomic integer, and then add some value to it, and that happens as one atomic operation, meaning that no other thread can get to it until it finishes, or there’s a compareAndSet, which says that take a look at the current value, if it matches a value, pass it in, then set it to another value, and that all runs atomically, guaranteeing that nothing else gets in between during those operations. SO as you can see, Java provides everything we need to write effective, high-performing, multithreaded concurrent applications.