Advantages and disadvantages of concurrent programming (-)

Time:2021-8-28

1.Why concurrency

For a long time, the development of hardware has been extremely rapid, and there is also a very famous “Moore’s law“. It may be strange that it is clearly discussed why concurrent programming involves the development of hardware. The relationship should be the hardware foundation provided by the development of multi-core CPU for concurrent programming. Moore’s law is not a natural law or a physical law. It is only a prediction of the future based on the observed data. According to the predicted speed, our computing power will grow at an exponential rate, and we will have super computing power in the near future. It is just when we imagine the future. In 2004, Intel announced that the plan of 4GHz chip was postponed to 2005, and then in the autumn of 2004, Intel announced that it would completely cancel the plan of 4GHz, In other words, the validity of Moore’s law has stopped abruptly for more than half a century. However, smart hardware engineers did not stop the pace of research and development. In order to further improve the computing speed, instead of pursuing a separate computing unit, they integrated multiple computing units together, that is, formed a multi-core CPU. In just over a decade, home CPUs, such as Intel i7, can reach 4 cores or even 8 cores. Professional servers can usually reach several independent CPUs, and each CPU even has more than 8 cores. Therefore, Moore’s law seems to continue to be experienced on CPU core expansion. Therefore, in the context of multi-core CPU, the trend of concurrent programming has been promotedIn the form of concurrent programming, the computing power of multi-core CPU can be brought into full play and the performance can be improved

Donald Ervin Knuth, a top computer scientist, commented on this situation: in my opinion, this phenomenon (concurrency) is more or less due to the helplessness of hardware designers, who put the responsibility of Moore’s law on software developers.

In addition, in special business scenarios, it is inherently suitable for concurrent programming. For example, in the field of image processing, a 1024×768 pixel picture contains more than 786000 pixels. It takes a long time to traverse all pixels on one side. In the face of such complex computation, we need to make full use of the ability of multi-core computing. For another example, when we shop online, in order to improve the response speed, we need to split, reduce inventory, generate orders, etc. these operations can be split and completed by multi-threaded technology.In the face of complex business models, parallel programs will be more suitable for business needs than serial programs, and concurrent programming can better meet this business split。 It is precisely because of these advantages that multithreading technology can be valued and should be mastered by a CS learner:

  • Make full use of the computing power of multi-core CPU;
  • Facilitate business splitting and improve application performance

2. What are the disadvantages of concurrent programming

Multithreading technology has so many advantages. Isn’t there any disadvantage? Is it necessarily applicable in any scenario? Obviously not.

2.1 frequent context switching

The time slice is the time allocated by the CPU to each thread. Because the time is very short, the CPU constantly switches threads to make us feel that multiple threads execute at the same time. The time slice is generally tens of milliseconds. During each switching, the current state needs to be saved so that the previous state can be restored. This switching consumes performance very much, and it is too frequent to give full play to the advantages of multi-threaded programming.Generally, context switching can be reduced by using lock free concurrent programming, CAS algorithm, using the least threads and using CO processes.

  • Lock free concurrent programming: you can refer to the idea of lock segmentation in concurrenthashmap, and different threads process different segments of data. In this way, under the condition of multi-threaded competition, you can reduce the time of context switching.
  • CAS algorithm uses CAS algorithm under atomic to update data, and uses optimistic lock, which can effectively reduce some context switching caused by unnecessary lock competition
  • Use the least threads: avoid creating unnecessary threads. For example, there are few tasks, but many threads are created, which will cause a large number of threads to be waiting
  • Coroutine: realize the scheduling of multiple tasks in a single thread, and maintain the switching between multiple tasks in a single thread

Because context switching is also a relatively time-consuming operation, there was an experiment in the book “the art of Java Concurrent Programming”. Concurrent accumulation may not be faster than serial accumulation. have access toLbench3 measures the duration of context switching Vmstat measures the number of context switches

2.2 thread safety

The most difficult thing to grasp in multithreaded programming is the thread safety problem in the critical area. If you pay little attention, there will be a deadlock. Once a deadlock occurs, the system function will not be available.

public class DeadLockDemo {
    private static String resource_a = "A";
    private static String resource_b = "B";

    public static void main(String[] args) {
        deadLock();
    }

    public static void deadLock() {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource_a) {
                    System.out.println("get resource a");
                    try {
                        Thread.sleep(3000);
                        synchronized (resource_b) {
                            System.out.println("get resource b");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource_b) {
                    System.out.println("get resource b");
                    synchronized (resource_a) {
                        System.out.println("get resource a");
                    }
                }
            }
        });
        threadA.start();
        threadB.start();

    }
}
Copy code

In the above demo, two threads threada and threadb are started, in which threada occupies resources_ a. And wait for the resource released by threadb_ b。 Threadb takes up resources_ B is waiting for the resource released by threada_ a。 Therefore, threada and threadb have thread safety problems, resulting in deadlock. This inference can also be proved by JPS and jstack:

"Thread-1":
  waiting to lock monitor 0x000000000b695360 (object 0x00000007d5ff53a8, a java.lang.String),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x000000000b697c10 (object 0x00000007d5ff53d8, a java.lang.String),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at learn.DeadLockDemo$2.run(DeadLockDemo.java:34)
        - waiting to lock <0x00000007d5ff53a8(a java.lang.String)
        - locked <0x00000007d5ff53d8(a java.lang.String)
        at java.lang.Thread.run(Thread.java:722)
"Thread-0":
        at learn.DeadLockDemo$1.run(DeadLockDemo.java:20)
        - waiting to lock <0x00000007d5ff53d8(a java.lang.String)
        - locked <0x00000007d5ff53a8(a java.lang.String)
        at java.lang.Thread.run(Thread.java:722)

Found 1 deadlock.
Copy code

As mentioned above, you can fully see the current deadlock.

Then, you can usually avoid deadlock in the following ways:

  1. Avoid one thread obtaining multiple locks at the same time;
  2. Avoid one thread occupying multiple resources inside the lock, and try to ensure that each lock occupies only one resource;
  3. Try to use the timing lock. Use lock.trylock (timeout). When the timeout wait, the current thread will not block;
  4. For database locks, locking and unlocking must be in a database connection, otherwise unlocking will fail

Therefore, there is a lot of knowledge on how to correctly use multithreaded programming technology, such as how to ensure thread safety and how to correctly understand the problems caused by atomicity, ordering and visibility of JMM memory model, such as dirty data reading and DCL (which will be described in the following pages). In the process of learning multithreaded programming technology, you will also gain a lot.

3. Concepts that should be understood

3.1 synchronous vs asynchronous

Synchronous and asynchronous are often used to describe a method call. At the beginning of the synchronous method call, the caller must wait for the end of the invoked method to execute the code behind the caller. Asynchronous call means that the caller will continue to execute the following code regardless of whether the called method is completed. When the called method is completed, the caller will be notified. For example, when shopping overtime, if an item is gone, you have to wait for the warehouse personnel to transfer the goods with you. You can’t continue to pay at the cashier until the warehouse personnel deliver the goods to you, which is similar to synchronous call. Asynchronous call is like online shopping. After you pay and place an order online, you don’t have to worry about anything. You can do whatever you should do. When the goods arrive, you can receive a notice to pick them up.

3.2 concurrency and parallelism

Concurrency and parallelism are very confusing concepts. Concurrency refers to the alternation of multiple tasks, while parallelism refers to the real sense of “simultaneous”. In fact, if there is only one CPU in the system and multithreading is used, it can not be parallel in the real system environment. It can only be performed alternately by switching time slices, which becomes a concurrent task.True parallelism can only occur in systems with multiple CPUs.

3.3 blocking and non blocking

Blocking and non blocking are usually used to describe the interaction between multiple threads. For example, if a thread occupies a critical zone resource, other threads need this resource and must wait for the resource to be released, which will cause the waiting thread to hang. This situation is blocking, not blocking. On the contrary, it emphasizes that no thread can block other threads, All threads will try to run forward.

3.4 critical zone

Critical area is used to represent a common resource or shared data, which can be used by multiple threads. However, when each thread is used, once the critical area resources are occupied by one thread, other threads must wait.