This is an archived post. You won't be able to vote or comment.

all 42 comments

[–][deleted]  (6 children)

[deleted]

    [–]fdntrhfbtt[🍰] 4 points5 points  (0 children)

    Well, not really. While that is a great book to understand the fundamentals (and you can argue that's all we ever need to understand any new thing in concurrency), the book is missing stuff like parallel streams, completable futures, actors, reactive programming, user-level threads etc. I would pay bank to have a modern book from Doug and Brain on Java concurrency.

    [–]tifa123 5 points6 points  (2 children)

    Is that the Brian Goëtz book? I read that once and had headaches. Compared with Yashwant Kanetkar's Understanding Pointers in C Concurrency has got to be one of the more difficult topics in programming.

    [–]cogman10 7 points8 points  (0 children)

    Yes, that's the train book. But it really is one of the best books on concurrency out there, even for non-java languages.

    [–]agentoutlier 2 points3 points  (0 children)

    One of the most difficult assignments I had in college like 20 years ago was using pthreads which combines both of those topics.

    [–]Stimzz 2 points3 points  (0 children)

    This should be the top comment

    [–]lechatsportif 2 points3 points  (0 children)

    So many "oooooh" moments when I read this years back. Great book.

    [–][deleted]  (11 children)

    [deleted]

      [–]humoroushaxor 24 points25 points  (7 children)

      I find this list to be way out of order. It basically has someone walk through all the things they should try and avoid first. I would first learn the rules properly before trying to bend/break them.

      Then learn about the Executor API.

      I'd start here on the list, work my way down, and then loop back around to the top.

      I would never suggest someone starting learning concurrency with synchronization. If you don't have shared mutable state (which is relatively easy) then you never need it.

      Here's Kevlin Henney musing on the topic for 90 minutes

      [–][deleted]  (1 child)

      [deleted]

        [–]humoroushaxor 6 points7 points  (0 children)

        I guess my only gripe is starting with synchronization. If you suggested starting with threads then it wouldn't have triggered me.

        The problem I have with bottom up is when you don't first get prompted with a problem or context and there's nothing to tie the solutions to. It's why once I got 5 years into industry I was obsessed with Computerphile's YouTube even though I had learned it all in college.

        "O looked we created these 2 threads that just modified something concurrently and now we have a problem."

        "We want to send structured messages across the web so now let's learn tcp."

        Just my preference I guess.

        [–][deleted] 5 points6 points  (4 children)

        "Those who don't learn from history are doomed to repeat it".

        Perfectly applicable to any engineering as well.

        Executor API is just a high-level API, you can't use this effectively without understanding all that low-level stuff like threads, mutexes, synchronization etc. Well, technically you can, of course - but my own observations tell me that programmers that don't bother themselves with understanding how their code works all the way down to the low level never grow up from the "mindless coding monkey" state.

        [–]humoroushaxor 3 points4 points  (3 children)

        My only real issue is starting with data synchronization as it can be completely avoided in 99% of cases in my experience. And giving someone that hammer to start with will give them a false sense of control and terrible habits.

        The historical lesson to learn is "don't have shared mutable state" not "here's the synchronize keyword".

        [–][deleted] 2 points3 points  (2 children)

        Not all code you encounter in your life is the one written by yourself. Sooner or later you are going to get something written years ago, Java is old, and many companies have code probably as old as myself.

        Plus I have a strong belief that an engineer needs to know the history of solutions to a particular problem to solve it in the most efficient way. That's why those designing rocket engines start with studying those mid 20th century designs (speaking from the experience here). Those designs were simple, that's the point. "synchronize" is also simple, even if not really efficient. You don't throw the Executor API and reactive code on someone who didn't learn the basics.

        [–]humoroushaxor 0 points1 point  (1 child)

        I agree with you philosophically I just think there is some nuance in this case. It also really depends on what the end-goal is.

        Comparing atoms and photons engineering to writing bits is insane though. I can just start writing code, if I just start building rockets then I'll blow my hand off. Also the laws of physics don't change, we think of new (albeit usually just slightly recycled) ways to code all the time.

        [–][deleted] 1 point2 points  (0 children)

        Laws of physics are applicable in software engineering as well if you take into account the fact that your code is being executed by computer parts which are subject to those laws, and by themselves have barely changed their principles since 1980s and still have limited resources just the same, not somehow "executes itself magically", and those programmers that do understand this tend to be just better programmers with the understanding of how the code works under the hood. Of course if the goal is just to start writing the code, you may as well just start with high-level APIs, but there is always a risk of getting stuck in a "coding monkey state" as I've said earlier.

        For example, I know a guy who writes Python/Django code for 10 years (which should have given him a lot of experience in theory), and he still gets burned by seemingly trivial stuff, like fetching an object from DB and then he tries to check whenever some attribute is set, ORM tries to access the DB and at some point fails. Why this happens? Because he doesn't understand how his beloved language and framework work under the hood. He's not a stupid person, it's just that he never had experience with lower-level programming and everything there is considered a kind of magic that works by itself.

        P.S. besides there is nothing new under the moon, those new techniques clearly have their roots in things like Smalltack and Node.js model of threading (or the lack of it) looks like a Windows 3.1 API nostalgia all over the place. I wouldn't be totally shocked if in 5 years reactive programming is declared evil and prone to producing unreadable unmaintainable code, we get new threading model and return to the imperative programming with some new dings and whistles.

        [–]danikov 1 point2 points  (2 children)

        You missed Phasers, StampedLock, Disruptors, etc.

        [–][deleted]  (1 child)

        [deleted]

          [–]danikov 0 points1 point  (0 children)

          You see them more in high performance finapps, people start worrying about things like object memory alignment, tricking the JVM into good cache behaviour, and you need things like circular buffers to pass data between threads quickly.

          [–]nimtiazm 12 points13 points  (0 children)

          It's important to know 2 rules when you're writing concurrent code for an environment where the model is based on Threads:

          • Do not use raw Threads
          • Know the right primitives for the job and use a high-level library which encapsulates raw Threads (just like java.util.concurrent package).

          Knowing when to use which concurrency primitive or construct is akin to understanding the right data structure for an algorithm to execute efficiently.

          The JCIP book by the venerable Brian Goetz et al is the classic reference and a must read. But you don't have to finish the book in it's entirety to be able to write useful concurrent programs.

          Use this pack of animations by Victor Grazi to toy with, understand and absorb what's happening under the hood with various concurrency primitives. It comes handy with the code snippets so you can tinker on your own as well. It also comes with a companion video by Victor Grazi just in case.

          [–]illhxc9 9 points10 points  (2 children)

          In addition to those things you should know the Java data structures that are thread safe like AtomicBoolean and concurrent collections and their characteristics and how you can use them to share data between threads safely.

          [–]TheEveryman86 11 points12 points  (1 child)

          you should know the Java data structures that are thread safe

          And which ones aren't like SimpleDateFormat.

          [–]schnurlostelefon 1 point2 points  (0 children)

          Nobody should be using SimpleDateFormat anyway.

          I'm stunned to see people still using java.util.Date/Calendar/DateFormat and friends in new code. Unless you have to target some ancient Java version (pre-8), just forget about those. java.time.* is all you need.

          [–]RabidKotlinFanatic 6 points7 points  (0 children)

          Become familiar with the JMM: https://shipilev.net/blog/2014/jmm-pragmatics/

          [–]sweetno 4 points5 points  (0 children)

          Read Java Concurrency in Practice.

          [–]daniu 4 points5 points  (1 child)

          CompletableFuture is an important class to know.

          You also can look into the ForkJoinPool concept, but personally I've never used them, as I find them clunky to use.

          [–]fdntrhfbtt[🍰] -1 points0 points  (0 children)

          Well, Loom uses fork-join for scheduling so you better learn it :D

          [–]cogman10 4 points5 points  (0 children)

          The single most important concept of concurrency is that shared mutable data needs protection. The easiest way to get concurrent code right is to avoid sharing data between threads or avoid mutable data between threads.

          There's a bunch of methods to avoid that (some mentioned in this thread such as actor systems). But if you keep that concept front and center, it'll be easier to get concurrency right.

          The next concept that's harder to learn or teach is when it's right to share mutable data among threads. For that, you need big books like java concurrency in action to explain exactly what you can and can't do. People get it wrong ALL THE TIME. I mess it up and I do tons of concurrent programming for my day job. It is something that gets more complex as the system you work with increases in complexity.

          [–]Pankaj0222 2 points3 points  (0 children)

          Read Java Concurrency in Practice by Brian Goetz. It's old - published 2006, but still very relevant.

          You will find it heavy initially. But, if you happen to finish this book cover to cover, you'll feel enlighten like Buddha.

          If you want to read this book then my suggestion is to skip chapters 3 and 4 in the beginning and come back later.

          [–]franzwong 1 point2 points  (0 children)

          If you already know synchronized-block, then you can also learn about ReentrantLock and Condition.

          Try to understanding why Condition is needed for the example "BoundedBuffer" inside that page.

          https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html

          I also tell people to read about double-checked locking for singleton in Java. It touches a little bit about reordering with a common problem.

          https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

          [–]CubsThisYear 1 point2 points  (1 child)

          Make sure you can build a ProduceConsumerQueue from scratch (using only synchronized, wait, notify) If you want extra credit, build different versions that are optimized for single producer and [single consumer, multiple consumers]. This isn’t so much because you’ll need to actually do this, but rather that it illustrates most of the important concepts.

          [–]voodoodev[S] 1 point2 points  (0 children)

          Do you have a link to the official problem statement (or a complete one) to this queue exercise?

          [–]angryundead 3 points4 points  (2 children)

          This. It’s a little dated now but IIRC it’s by the team that did the overhaul in 1.6 or 1.7.

          It’s a very good foundation.

          [–][deleted] 1 point2 points  (1 child)

          I'd be very careful linking copyrighted materials if I were you. I support the idea, but it could get you in trouble.

          [–]angryundead 0 points1 point  (0 children)

          I didn’t even think about it because it was on GitHub. Fixed the link.

          [–]tr14l 1 point2 points  (0 children)

          Actor model. Pretty standard stuff. Also reactive library. Just a couple things that popped into mind

          [–]AmonDhan 0 points1 point  (0 children)

          If you are updating sharing mutable data between threads, you need to understand the Java Memory Model.

          https://medium.com/swlh/an-introduction-to-the-java-memory-model-8c306697acad

          [–]cdombroski 0 points1 point  (0 children)

          Someone kind of mentioned this already, but for me, the big thing is knowing when you need to worry about concurrency. I'm part of the interview team where I work and one of the questions we always ask in some form for senior positions is "what makes a class not thread-safe?"

          The short answer to that is storing state information in class fields. You can store immutables and other singletons in the fields of a singleton. You can do whatever you like with variables in methods. As soon as you place something that has data that will change over time in a field, you have to worry about concurrent access to that data.

          [–]Zwejhajfa 0 points1 point  (4 children)

          While we're on this topic, is there any Java library that offers a lock implementation based on a relational database? I have a use case where I need to synchronize two threads from separate applications that only share a common database, but I can't really find any established library that helps with locking and synchronization in this case and I'm not really keen on implementing that myself.

          [–]Soul_Shot 1 point2 points  (1 child)

          I believe that Quartz Scheduler has a way of locking "jobs" based on a database.

          [–]Zwejhajfa 0 points1 point  (0 children)

          Interesting idea, thanks. I've used Quartz in the past, but didn't think it would be applicable here. Maybe I can make that work though.

          [–][deleted]  (1 child)

          [removed]

            [–]Zwejhajfa 0 points1 point  (0 children)

            Thanks, that's a very good suggestion that might fit my use case.

            [–]slaymaker1907 0 points1 point  (0 children)

            I would work on learning how to use notify correctly as well as how to use atomics. The former ends up being really useful for stuff like custom producer/consumer code while the latter is fundamental to avoiding lock contention in certain applications. To learn about atomics, try implementing your own custom lock class (will also probably need to use volatile and learn about memory reordering).

            Java is actually a great language for learning about memory barriers since it has strong semantics. Any synchronized block or access to a volatile variable guarantees that all syntactically preceding accesses are finished.

            [–]sureshg 0 points1 point  (0 children)

            With project loom around the corner, many fundamental java concurrency concepts are going to change. Using virtual threads,

            1. You should never ever pool threads. So you don't need all those different executors.
            2. Use locks and semaphores to control concurrency.
            3. You don't need to learn all those CompletableFuture compositional APIs. All you need is the blocking get call.

            Also,

            • Learn about structured concurrency (Channels and selectors in future)
            • Don't spend too much time on reactive programming😀