00 Preface the Reasons Why You Need to Learn and Practice Programming

00 Preface The reasons why you need to learn and practice programming #

Hello, I’m Wang Baoling, a senior architect, currently working on the design of e-commerce architecture. Since graduating, I have been writing code for 15 years. When I first graduated, I worked on developing securities business applications using C/C++. Then I moved on to ERP product development using mainly C# and Java. In recent years, I have been working on the design and development of Java development platforms and basic middleware.

I still remember the first project I worked on after graduating was related to securities. A colleague from abroad wrote a memory database in C language, and the code was extremely concise and elegant. At that time, I looked at the code with deep respect and learned a lot from it. However, along with the excitement, I also felt some anxiety because there was a piece of concurrent-related code that I found difficult to understand. I felt like I didn’t fully grasp it.

Subconsciously, I told myself that my knowledge in this area was not enough, so I needed to study hard and practice diligently. You know, 15 years ago, there were not many learning materials available on this topic. My mentor recommended the book “Operating System Principles” to me, saying, “The earliest application field of concurrent programming is the implementation of operating systems. If you understand this book, you will naturally solve the problem of concurrency.” However, there was always a gap between theory and practice, and for many years, I felt most helpless when dealing with concurrent-related issues.

Mastering concurrent programming is not an easy process. I believe that in order to solve this problem, you may have heard others summarize the first principle of concurrent programming, which is “don’t write concurrent programs.” This principle used to be applicable in the first few years after I graduated. At that time, multi-core servers were still a luxury, and system concurrency was low. We could basically rely on databases and middleware like Tomcat without having to write concurrent programs. Or, you could say that concurrency issues were mostly solved by middleware and databases.

But in recent years, concurrent programming has gradually become an essential skill.

This is mainly driven by hardware advances and the rapid development of the domestic Internet industry. Now, 64-core servers have become commonplace, and large-scale Internet companies easily achieve concurrency of over a million. Traditional middleware and databases can no longer provide adequate support and have become bottlenecks instead.

Therefore, concurrent programming has become a very popular and scarce talent in recent years. However, at the same time, there has been a gradual increase in books on concurrent programming. So when the team at Geektime approached me to discuss this column, my first question was whether it was necessary to create such a column since there are already many excellent books on this topic available in the market.

But after thinking deeply, I became determined to write. Most of the colleagues I have been in contact with in recent years have been able to make rapid progress in their technical skills after working for a few years, but they still struggle with concurrent programming. Although they are familiar with concurrent libraries, they always fail to write correct and efficient concurrent programs. What is the reason? I found that many people have blind spots in certain areas, overlooking some details, but it is precisely these details that determine the correctness and efficiency of a program.

This blind spot sometimes involves an understanding of operating systems and sometimes a bit of hardware knowledge. It is very complex, and if we were to recommend related books, it might require several books, which would be quite inefficient. At the same time, books tend to pursue rigor but may lose their readability, making the reading process quite difficult.

I believe that if we can address these issues, then doing this would be meaningful.

For example, the knowledge of synchronized, wait()/notify() in Java is fragmented and difficult to understand, and even more difficult to use. But in reality, synchronized, wait(), and notify() are just one implementation of the monitor model in the field of operating systems. The concept of condition variables in the Java SDK’s concurrency package is also a concept in the monitor model. If you understand these knowledge fragments separately, it will naturally be like peering through a small hole. However, if you stand at the height of the monitor model theory, you will discover that these knowledge fragments are actually quite simple, and using them will become second nature.

As a model for solving concurrent problems, the monitor model was a major innovation after the semaphore model. It is logically equivalent to semaphores (semaphores can be implemented using monitors, and monitors can be implemented using semaphores), but compared to semaphores, monitors are easier to use. Furthermore, many programming languages support monitors, and understanding monitors is very helpful for learning concurrent programming in other languages. However, many people are eager to learn Java concurrent programming techniques but overlook the theory and models behind the technology, which are often more important than the specific techniques themselves. In addition, after years of development, Java has provided a rich set of features in its concurrent package. For beginners, it can be overwhelming and many people feel lost. However, the Java concurrent package is created by the concurrency master Doug Lea and is considered a classic. It must have a clear structure internally. So, where is its structure?

In fact, concurrent programming can be summarized into three core problems: division of labor, synchronization, and mutual exclusion.

The concept of division of labor refers to how to efficiently decompose tasks and assign them to threads. Synchronization is about how threads collaborate, while mutual exclusion ensures that only one thread can access shared resources at any given time. The content in the Java concurrent package is largely organized according to these three dimensions. For example, the Fork/Join framework is a form of division of labor, CountDownLatch is a typical synchronization method, and reentrant locks are a means of mutual exclusion.

When you understand the core problems of concurrent programming, then look back at the Java concurrent package, you will feel enlightened. It is just a tool developed for dealing with concurrent problems. At this point, you can master the concurrent package.

Moreover, these three core problems are not specific to Java but are applicable to other languages as well. If you want to learn concurrent programming libraries in other languages, you can follow these three problems to find relevant solutions. The remaining part of the Java concurrent package includes concurrent containers and atomic classes, which are relatively easy to understand and are auxiliary tools. Equivalent features can be found in other languages.

So, is concurrent programming difficult to learn?

First of all, it is definitely difficult because it involves knowledge from various aspects such as operating systems, CPUs, and memory. If you lack knowledge in a certain area, understanding concurrent programming can naturally become difficult. Secondly, whether it is difficult to learn or not can vary from person to person. Based on my experience, many people tend to start from specific points when learning concurrent programming, hoping to find patterns or essence within those points, but end up confusing themselves.

As I mentioned before, concurrent programming is not specific to Java. It is a universal and mature field. Java merely implemented it based on its own circumstances. When you understand or learn concurrent programming, if you can think about the problem systematically from a higher level, based on theory and models, it will be much easier.

Therefore, I hope that this column will focus more on the essence behind the problems, the origin of the problems, and explain Java concurrency from a theoretical and model-based perspective so that your knowledge becomes systematic and coherent. Ultimately, it will enable you to solve various concurrency challenges with ease and apply this knowledge to other programming languages, allowing you to achieve more with less effort.

Of course, we need to persevere and not be inconsistent. Rome wasn’t built in a day.

Many people say that learning goes against human nature. It is easy to start, but it is difficult to persevere in the long term. I agree with this. During interviews, I often ask candidates the following question: “In your work, have you ever persisted with something for a long time and benefited from it?” If the candidate can answer this question, it will be a plus during the entire interview. I believe that perseverance is truly valuable. Some people are only enthusiastic for a short period of time, while others can persist for a year or even longer. If you look at it over a longer period of time, the difference in achievements between these two types of people can be exponential.

I hope you can persevere with me. Let us learn and communicate together. When encountering problems, instead of simply complaining and avoiding, let us strive to find answers and solutions. This time, let’s persevere in exploring the mysteries of concurrent programming and experience the joy of knowledge exploration. Today’s article is an opening word. The main content will come soon. If possible, please introduce yourself and chat with me in the comments section about your current work, learning situation, and the difficulties you face in concurrent programming. This will enable me to provide targeted explanations later on. In this way, we can understand each other better.